📝 first push of docs

This commit is contained in:
Joe Kaufeld 2024-08-26 01:56:56 -04:00
parent 3ab9e05442
commit 42552e2dbc
15 changed files with 245 additions and 0 deletions

44
docs/README.md Normal file
View File

@ -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

View File

@ -0,0 +1 @@
https://www.hubspot.com/hubfs/brand-kit-generator/prototype/fonts/DMSans-Bold.ttf

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
docs/_media/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

6
docs/_sidebar.md Normal file
View File

@ -0,0 +1,6 @@
- [home](README.md)
- [quickstart](quickstart.md)
- [responses](responses.md)
- Middleware
- [middleware](middleware/test.md)
- [middleware2](middleware/test2.md)

12
docs/example.md Normal file
View File

@ -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'.

44
docs/index.html Normal file
View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Description">
<link rel="icon" type="image/png" sizes="32x32" href="/_media/Favicon-32x32.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
</head>
<body>
<style>
@font-face {
font-family: "DMSans";
src: url('_media/DMSans-Medium.ttf') format('truetype');
}
body {
font-family: "DMSans", sans-serif;
}
</style>
<div id="app"></div>
<script>
window.$docsify = {
name: 'Spiderweb',
loadSidebar: true,
repo: 'https://github.com/itsthejoker/spiderweb',
maxLevel: 3,
coverpage: true,
'flexible-alerts': {
style: 'callout' // or 'flat'
},
auto2top: true,
}
</script>
<!-- Docsify v4 -->
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-python.min.js"></script>
<!-- admonitions -->
<script src="https://unpkg.com/docsify-plugin-flexible-alerts"></script>
<script src="//unpkg.com/docsify-pagination/dist/docsify-pagination.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/docsify-tabs@1"></script>
</body>
</html>

1
docs/middleware/test.md Normal file
View File

@ -0,0 +1 @@
asdf

1
docs/middleware/test2.md Normal file
View File

@ -0,0 +1 @@
asdfawaasdf

93
docs/quickstart.md Normal file
View File

@ -0,0 +1,93 @@
# quickstart
Start by installing the package with your favorite package manager:
<!-- tabs:start -->
<!-- tab:poetry -->
```shell
poetry add spiderweb-framework
```
<!-- tab:pip -->
```shell
pip install spiderweb-framework
```
<!-- tab:pipenv -->
```shell
pipenv install spiderweb-framework
```
<!-- tabs:end -->
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.

3
docs/responses.md Normal file
View File

@ -0,0 +1,3 @@
# responses
...

40
test.py Normal file
View File

@ -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])