====== APIs amb Django Ninja ======
Django Ninja és una llibreria per a fer APIs alternativa a la clàssica Django REST Framework (que podeu veure a l'article [[Django API]]) i fortament inspirada en la molt adoptada recentment [[https://fastapi.tiangolo.com/|FastAPI]].
El principal avantatge és certa simplicitat per crear els endpoints.
Referències:
* [[Django API]] en aquesta wiki.
* Web oficial de Django Ninja: https://django-ninja.dev/
{{tag> #FpInfor #Daw #DawMp07 #DawMp07Uf4 #DawMp07Uf04 django web api framework rest }}
\\
===== Quickstart =====
És relativament fàcil acostar-se a Django Ninja amb la seva documentació:
* Iniciar projecte i arxiu ''api.py'': https://django-ninja.dev/tutorial/
* Un exemple de CRUD complet: https://django-ninja.dev/tutorial/other/crud/
\\
===== Autenticació =====
Destaquem dos mètodes d'autenticació molt estandarditzats:
* **Basic Authentication** : amb usuari i contrasenya. Convé no fer-la servir sovint ja que la contrasenya és una dada sensible. La clàssica crida a un endpoint amb aquest mecanisme seria:curl http://localhost:8000/api/token/ -u manolo:pass123
* **Token Authentication** : millora la seguretat en les crides a l'API, enviant un //token// enlloc de la contrasenya. El //token// es pot obtenir, per exemple, per Basic Authentication. Les crides a l'API s'han d'acompanyar del //token// sempre, i es pot fer de diverses formes de la qual destaquem el //header Bearer//:curl -H 'Authorization: Bearer 1d895b9062512a731b1e5667bd034da3' http://localhost:8000/api/llibres
Es poden implementar les dues amb aquest codi:
from django.contrib.auth import authenticate
from ninja import NinjaAPI, Schema
from ninja.security import HttpBasicAuth, HttpBearer
from typing import List, Optional
from .models import *
import secrets
api = NinjaAPI()
# Autenticació bàsica
class BasicAuth(HttpBasicAuth):
def authenticate(self, request, username, password):
user = authenticate(username=username, password=password)
if user:
# Genera un token simple
token = secrets.token_hex(16)
user.auth_token = token
user.save()
return token
return None
# Autenticació per Token Bearer
class AuthBearer(HttpBearer):
def authenticate(self, request, token):
try:
user = Usuari.objects.get(auth_token=token)
return user
except Usuari.DoesNotExist:
return None
# Endpoint per obtenir un token, accés amb BasicAuth
# amb o sense "trailing slash"
@api.get("/token", auth=BasicAuth())
@api.get("/token/", auth=BasicAuth())
def obtenir_token(request):
return {"token": request.auth}
# Exemple d'endpoint per llistar els llibres, accés amb TokenAuth
class LlibreOut(Schema):
id: int
titol: str
editorial: Optional[str]
@api.get("/llibres/", response=List[LlibreOut], auth=AuthBearer())
def get_llibres(request):
qs = Llibre.objects.all()
return qs
A part, també caldrà afegir la columna ''auth_token'' al model ''Usuari'' que cal personalitzar:
from django.contrib.auth.models import AbstractUser
class Usuari(AbstractUser):
auth_token = models.CharField(max_length=32,blank=True,null=True)
# + altres atributs que es vulguin afegir...
I a ''settings.py'':
AUTH_USER_MODEL = 'myapp.Usuari'
\\
===== Mes curl =====
El típic exemple de request amb Basic Authentication seria:
curl -u admin:admin123 http://localhost:8000/api/users/
De vegades ens pot interessar una alternativa enviant les dades codificades en base64 en els //headers//:
curl -H 'Authorization:Basic YWRtaW46YWRtaW4xMjM=' http://localhost:8000/api/users/
Per obtenir el //hash// en base64 es pot fer:
echo -n "admin:admin123" | base64
Per aconseguir un //pretty print// del JSON es pot fer amb la [[https://jqlang.org/tutorial/|utilitat jq]]
curl -u admin:admin123 http://localhost:8000/api/users/ | jq
Per instal·lar jq es pot fer:
sudo apt install jq