ohmyapi/README.md

258 lines
5.1 KiB
Markdown
Raw Normal View History

2025-09-27 00:29:45 +02:00
# OhMyAPI
> Think: Micro-Django, but API-first, less clunky and 100% async.
2025-09-27 00:29:45 +02:00
2025-09-27 12:46:38 +02:00
OhMyAPI is a Django-flavored web-application scaffolding framework and management layer.
Built around FastAPI and TortoiseORM, it is 100% async.
2025-09-27 00:29:45 +02:00
It is ***blazingly fast***, ***fun*** to use and comes with ***batteries included***!
**Features**
2025-09-27 00:29:45 +02:00
- Django-like project-layout and -structure
2025-09-27 12:46:38 +02:00
- Django-like prject-level settings.py
2025-09-27 00:29:45 +02:00
- Django-like models via TortoiseORM
2025-09-27 12:46:38 +02:00
- Django-like `Model.Meta` class for model configuration
- Easily convert your query results to `pydantic` models via `Model.Schema`
2025-09-27 00:29:45 +02:00
- Django-like migrations (makemigrations & migrate) via Aerich
- Django-like CLI tooling (`startproject`, `startapp`, `shell`, `serve`, etc)
- Various optional builtin apps you can hook into your project
2025-09-27 12:46:38 +02:00
- Highly configurable and customizable
2025-09-27 00:29:45 +02:00
- 100% async
---
2025-09-27 00:29:45 +02:00
## Getting started
**Creating a Project**
```
pip install ohmyapi
2025-09-27 00:29:45 +02:00
ohmyapi startproject myproject
cd myproject
```
This will create the following directory structure:
```
myproject/
- pyproject.toml
2025-09-27 12:46:38 +02:00
- README.md
2025-09-27 00:29:45 +02:00
- settings.py
```
Run your project with:
```
ohmyapi serve
```
In your browser go to:
- http://localhost:8000/docs
**Creating an App**
Create a new app by:
```
ohmyapi startapp tournament
2025-09-27 00:29:45 +02:00
```
This will create the following directory structure:
2025-09-27 00:29:45 +02:00
```
myproject/
- tournament/
2025-09-27 00:29:45 +02:00
- __init__.py
- models.py
- routes.py
- pyproject.toml
2025-09-27 12:46:38 +02:00
- README.md
2025-09-27 00:29:45 +02:00
- settings.py
```
Add 'tournament' to your `INSTALLED_APPS` in `settings.py`.
2025-09-27 00:29:45 +02:00
### Models
Write your first model in `turnament/models.py`:
2025-09-27 00:29:45 +02:00
```python
from ohmyapi.db import Model, field
class Tournament(Model):
id = field.IntField(primary_key=True)
name = field.TextField()
created = field.DatetimeField(auto_now_add=True)
def __str__(self):
return self.name
class Event(Model):
id = field.IntField(primary_key=True)
name = field.TextField()
tournament = field.ForeignKeyField('tournament.Tournament', related_name='events')
participants = field.ManyToManyField('torunament.Team', related_name='events', through='event_team')
modified = field.DatetimeField(auto_now=True)
prize = field.DecimalField(max_digits=10, decimal_places=2, null=True)
def __str__(self):
return self.name
class Team(Model):
id = field.IntField(primary_key=True)
name = field.TextField()
def __str__(self):
return self.name
2025-09-27 00:29:45 +02:00
```
### API Routes
Next, create your endpoints in `tournament/routes.py`:
2025-09-27 00:29:45 +02:00
```python
from ohmyapi.router import APIRouter, HTTPException
from ohmyapi.db.exceptions import DoesNotExist
2025-09-27 00:29:45 +02:00
from .models import Tournament
2025-09-27 00:29:45 +02:00
router = APIRouter(prefix="/tournament")
2025-09-27 00:29:45 +02:00
@router.get("/")
async def list():
queryset = Tournament.all()
return await Tournament.Schema.many.from_queryset(queryset)
2025-09-27 00:29:45 +02:00
@router.get("/:id")
async def get(id: int):
try:
queryset = Tournament.get(pk=id)
return await Tournament.Schema.one(queryset)
2025-09-27 00:29:45 +02:00
except DoesNotExist:
raise HTTPException(status_code=404, detail="item not found")
...
```
## Migrations
Before we can run the app, we need to create and initialize the database.
Similar to Django, first run:
```
ohmyapi makemigrations [ <app> ] # no app means all INSTALLED_APPS
```
2025-09-27 05:00:58 +02:00
This will create a `migrations/` folder in you project root.
```
myproject/
- tournament/
2025-09-27 05:00:58 +02:00
- __init__.py
- models.py
- routes.py
- migrations/
- tournament/
2025-09-27 05:00:58 +02:00
- pyproject.toml
2025-09-27 12:46:38 +02:00
- README.md
2025-09-27 05:00:58 +02:00
- settings.py
```
Apply your migrations via:
2025-09-27 00:29:45 +02:00
```
ohmyapi migrate [ <app> ] # no app means all INSTALLED_APPS
```
Run your project:
```
ohmyapi serve
```
## Shell
Similar to Django, you can attach to an interactive shell with your project already loaded inside.
```
ohmyapi shell
```
## Authentication
A builtin auth app is available.
2025-09-27 05:00:58 +02:00
2025-09-27 00:29:45 +02:00
Simply add `ohmyapi_auth` to your INSTALLED_APPS and define a JWT_SECRET in your `settings.py`.
2025-09-27 12:46:38 +02:00
Remember to `makemigrations` and `migrate` for the necessary tables to be created in the database.
2025-09-27 00:29:45 +02:00
`settings.py`:
```
INSTALLED_APPS = [
'ohmyapi_auth',
...
]
JWT_SECRET = "t0ps3cr3t"
```
2025-09-27 05:09:07 +02:00
After restarting your project you will have access to the `ohmyapi_auth` app.
It comes with a `User` and `Group` model, as well as endpoints for JWT auth.
You can use the models as `ForeignKeyField` in your application models:
```python
class Team(Model):
[...]
members = field.ManyToManyField('ohmyapi_auth.User', related_name='tournament_teams', through='tournament_teams')
[...]
```
Remember to run `makemigrations` and `migrate` in order for your model changes to take effect in the database.
2025-09-27 05:09:07 +02:00
Create a super-user:
```
ohmyapi createsuperuser
```
## Permissions
### API-Level
Use FastAPI's `Depends` pattern to implement API-level access-control.
In your `routes.py`:
```python
from ohmyapi.router import APIRouter, Depends
from ohmyapi_auth.models import User
from ohmyapi_auth import (
models as auth,
permissions,
)
from .models import Tournament
router = APIRouter(prefix="/tournament")
@router.get("/")
async def list(user: auth.User = Depends(permissions.require_authenticated)):
queryset = Tournament.all()
return await Tournament.Schema.many.from_queryset(queryset)
...
```