diff --git a/spiderweb/tests/test_spiderweb.py b/docs/.nojekyll similarity index 100% rename from spiderweb/tests/test_spiderweb.py rename to docs/.nojekyll diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..9365dac --- /dev/null +++ b/docs/README.md @@ -0,0 +1,44 @@ +# spiderweb + +As a professional web developer focusing on arcane uses of Django for arcane purposes, it occurred to me a little while ago that I didn't actually know how a web framework _worked_. + +> So I built one. + +This is `spiderweb`, a web framework that's just big enough to hold a spider. When building it, my goals were simple: + +- Learn a lot +- Create an unholy blend of Django and Flask +- Not look at any existing code. Go off of vibes alone and try to solve all the problems I could think of in my own way + +> [!WARNING] +> This is a learning project. It should not be used for production without heavy auditing. It's not secure. It's not fast. It's not well-tested. It's not well-documented. It's not well-anything. It's a learning project. +> +> That being said, it's fun and it works, so I'm counting that as a win. + + +Here's a non-exhaustive list of things this can do: + + * Function-based views + * Optional Flask-style URL routing + * Optional Django-style URL routing + * URLs with variables in them a lá Django + * Full middleware implementation + * Limit routes by HTTP verbs + * (Only GET and POST are implemented right now) + * Custom error routes + * Built-in dev server + * Gunicorn support + * HTML templates with Jinja2 + * Static files support + * Cookies (reading and setting) + * Optional append_slash (with automatic redirects!) + * ~~CSRF middleware implementation~~ (it's there, but it's crappy and unsafe. This might be beyond my skillset.) + * Optional POST data validation middleware with Pydantic + * Database support (using Peewee, but the end user can use whatever they want as long as there's a Peewee driver for it) + * Session middleware with built-in session store + * Tests (currently a little over 80% coverage) + +The TODO list: + + * Fix CSRF middleware + * Add more HTTP verbs diff --git a/docs/_media/DMSans-Bold.ttf b/docs/_media/DMSans-Bold.ttf new file mode 100644 index 0000000..9e0ffa3 --- /dev/null +++ b/docs/_media/DMSans-Bold.ttf @@ -0,0 +1 @@ +https://www.hubspot.com/hubfs/brand-kit-generator/prototype/fonts/DMSans-Bold.ttf \ No newline at end of file diff --git a/docs/_media/DMSans-Medium.ttf b/docs/_media/DMSans-Medium.ttf new file mode 100644 index 0000000..841d31d Binary files /dev/null and b/docs/_media/DMSans-Medium.ttf differ diff --git a/docs/_media/Favicon-32x32.png b/docs/_media/Favicon-32x32.png new file mode 100644 index 0000000..ed5c9a5 Binary files /dev/null and b/docs/_media/Favicon-32x32.png differ diff --git a/docs/_media/favicon.png b/docs/_media/favicon.png new file mode 100644 index 0000000..ed5c9a5 Binary files /dev/null and b/docs/_media/favicon.png differ diff --git a/docs/_media/spiderweb_logo.png b/docs/_media/spiderweb_logo.png new file mode 100644 index 0000000..91b7c9a Binary files /dev/null and b/docs/_media/spiderweb_logo.png differ diff --git a/docs/_sidebar.md b/docs/_sidebar.md new file mode 100644 index 0000000..1a1fd70 --- /dev/null +++ b/docs/_sidebar.md @@ -0,0 +1,6 @@ +- [home](README.md) +- [quickstart](quickstart.md) +- [responses](responses.md) +- Middleware + - [middleware](middleware/test.md) + - [middleware2](middleware/test2.md) \ No newline at end of file diff --git a/docs/example.md b/docs/example.md new file mode 100644 index 0000000..b1289fd --- /dev/null +++ b/docs/example.md @@ -0,0 +1,12 @@ + +> [!ATTENTION] +> An alert of type 'attention' using global style 'callout'. + +> [!TIP] +> An alert of type 'tip' using global style 'callout'. + +> [!WARNING] +> An alert of type 'warning' using global style 'callout'. + +> [!NOTE] +> An alert of type 'note' using global style 'callout'. \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..b4b94b8 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,44 @@ + + + + + Document + + + + + + + + +
+ + + + + + + + + + diff --git a/docs/middleware/test.md b/docs/middleware/test.md new file mode 100644 index 0000000..5e40c08 --- /dev/null +++ b/docs/middleware/test.md @@ -0,0 +1 @@ +asdf \ No newline at end of file diff --git a/docs/middleware/test2.md b/docs/middleware/test2.md new file mode 100644 index 0000000..eb0fb96 --- /dev/null +++ b/docs/middleware/test2.md @@ -0,0 +1 @@ +asdfawaasdf \ No newline at end of file diff --git a/docs/quickstart.md b/docs/quickstart.md new file mode 100644 index 0000000..046291f --- /dev/null +++ b/docs/quickstart.md @@ -0,0 +1,93 @@ +# quickstart + +Start by installing the package with your favorite package manager: + + + + + +```shell +poetry add spiderweb-framework +``` + + + +```shell +pip install spiderweb-framework +``` + + + +```shell +pipenv install spiderweb-framework +``` + + + +Then, create a new file and drop this in it: + +```python +from spiderweb import SpiderwebRouter +from spiderweb.response import HttpResponse + +app = SpiderwebRouter() + +@app.route("/") +def index(request): + return HttpResponse("HELLO, WORLD!") + +if __name__ == "__main__": + app.start() +``` + +Start the dev server by running `python {yourfile.py}` and navigating to `http://localhost:8000/` in your browser. You should see `HELLO, WORLD!` displayed on the page. Press `Ctrl+C` to stop the server. + +That's it! You've got a working web app. Let's take a look at what these few lines of code are doing: + +```python +from spiderweb import SpiderwebRouter +``` + +The `SpiderwebRouter` class is the main object that everything stems from in `spiderweb`. It's where you'll set your options, your routes, and more. + +```python +from spiderweb.response import HttpResponse +``` + +Rather than trying to infer what you want, spiderweb wants you to be specific about what you want it to do. Part of that is the One Response Rule: + +> Every view must return a Response, and each Response must be a specific type. + +There are four different types of responses; if you want to skip ahead, hop over to [the responses page](responses.md) to learn more. For this example, we'll focus on `HttpResponse`, which is the base response. + +```python +app = SpiderwebRouter() +``` + +This line creates a new instance of the `SpiderwebRouter` class and assigns it to the variable `app`. This is the object that will handle all of your requests and responses. If you need to pass any options into spiderweb, you'll do that here. + +```python +@app.route("/") +def index(request): + return HttpResponse("HELLO, WORLD!") +``` + +This is an example view. There are a few things to note here: + +- The `@app.route("/")` decorator tells spiderweb that this view should be called when the user navigates to the root of the site. +- The `def index(request):` function is the view itself. It takes a single argument, `request`, which is a `Request` object that contains all the information about the incoming request. +- The `return HttpResponse("HELLO, WORLD!")` line is the response. In this case, it's a simple `HttpResponse` object that contains the string `HELLO, WORLD!`. This will be sent back to the user's browser. + +> [!TIP] +> Every view must accept a `request` object as its first argument. This object contains all the information about the incoming request, including headers, cookies, and more. +> +> There's more that we can pass in, but for now, we'll keep it simple. + +```python +if __name__ == "__main__": + app.start() +``` + +Once you finish setting up your app, it's time to start it! You can start the dev server by just calling `app.start()` (and its counterpart `app.stop()` to stop it). This will start a simple server on `localhost:8000` that you can access in your browser. It's not a secure server; don't even think about using it in production. It's just good enough for development. + +Now that your app is done, you can also run it with Gunicorn by running `gunicorn --workers=2 {yourfile}:app` in your terminal. This will start a Gunicorn server on `localhost:8000` that you can access in your browser and is a little more robust than the dev server. \ No newline at end of file diff --git a/docs/responses.md b/docs/responses.md new file mode 100644 index 0000000..4ad160b --- /dev/null +++ b/docs/responses.md @@ -0,0 +1,3 @@ +# responses + +... \ No newline at end of file diff --git a/test.py b/test.py new file mode 100644 index 0000000..04eaa41 --- /dev/null +++ b/test.py @@ -0,0 +1,40 @@ +from peewee import * +from playhouse.migrate import SqliteMigrator, migrate + +from spiderweb.db import SpiderwebModel + +db = SqliteDatabase("people.db") +migrator = SqliteMigrator(db) + + +class Person(SpiderwebModel): + name = CharField() + birthday = DateField() + + class Meta: + database = db # This model uses the "people.db" database. + + +class Pet(SpiderwebModel): + owner = ForeignKeyField(Person, backref="pets") + name = CharField(max_length=40) + animal_type = CharField() + age = IntegerField(null=True) + favorite_color = CharField(null=True) + + class Meta: + database = db # this model uses the "people.db" database + + +if __name__ == "__main__": + db.connect() + Pet.check_for_needed_migration() + # try: + # Pet.check_for_needed_migration() + # except: + # migrate( + # migrator.add_column( + # Pet._meta.table_name, 'favorite_color', CharField(null=True) + # ), + # ) + db.create_tables([Person, Pet])