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