DRF 보다 빠르고, 추상화가 적어서 사용자가 자유롭게 파라미터를 정의할 수 있는 도구 입니다. 이번 페이지 에서는 Django Ninja Tutorial 내용을 정리하면서 핵심적인 내용들을 요약해 보도록 하겠습니다.
Contents
Request Body
- Ninja API
- Schema Data Model
- Request body with
path & Query parameters
이렇게 구성되어 있습니다. API 연결하는 Serializer
를 사용할 때에는, Schema Class
에서 함수 (value()) 를 정의해서 활용할 수 있습니다.
# Example 1 (inline Schema)
@api.get("/items/{int:item_id}")
def read_item(request, item_id:int):
return {"item_id": item_id}
# Example 2 (Schema Class)
import datetime
from ninja import Schema, Path
## Schema Data Model
class PathDate(Schema):
year: int
month: int
def value(self):
return datetime.date(self.year, self.month)
## Request body
@api.get("/events/{year}/{month}") # Path parameters
def events(request, date: PathDate = Path(...)): # Query parameters
return {"date": date.value()}
Path & Query Parameters
Path
와 Query
에서 정의한 파라미터 변수의 이름을 일치 시키면, 자동으로 상호 동작을 합니다.
이때 파라미터 변수가 필수인지 여부는, 초깃값을 설정 여부 에 따라서 결정 됩니다. 초깃값을 입력하면 그에 따라서 Request Body
함수결과를 출력 합니다. 초깃값이 없으면 사용자가 필수로 입력을 해야만 함수가 동작하는 구조로 되어 있습니다.
Response Schema
@api.get("product/{project_id}", response=ProjectOut)
def get_project(request, project_id:int):
return get_object_or_404(Project, id=project_id)
@api.api_operation(['PUT','PATCH'], "product/{project_id}")
def update_project(request, project_id:int, payload: ProjectUpdate):
project = get_object_or_404(Project, id=project_id)
for key, value in payload.dict().items():
setattr(project, key, value)
project.save()
조작할 변수가 많고 복잡해 지는 경우에는 보다 효과적인 방법을 필요로 하게 되는데, from ninja import Path 를 Query parametor
에 사용 합니다.
Form Data
Post Form 형식의 API 를 사용할 때에는 request.POST
데이터를 application x-www-form-urlencoded or multipart/form-data
포맷으로 전송해야 합니다.
from ninja import Form
@api.post("/login")
def login(request, user:str=Form(...), psword:str=Form(...)):
return {'user': user, 'psword': '*****'}
앞에서 살펴본 Path
함수와 동일하게 Form
함수를 사용하면 Schema
클래스를 바로 Queryset
의 파라미터로 재활용 할 수 있습니다. Schema 재활용과 함께 inline 방식을 혼합하여 사용할 수 있습니다.
class Item(Schema):
name: str
description: str = None
price: float
quantity: int
@api.post("/items/{item_id}")
def update(request, item_id: int, q: str, item: Item=Form(...)):
return {"item_id": item_id, "item": item.dict(), "q": q}
File Upload
Django 의 FileField 를 API 로 작업할 때에 활용하는 예시 입니다.
from ninja import NinjaAPI, File
from ninja.files import UploadedFile
from typing import List
@api.post("/upload")
def upload(request, file: UploadedFile = File(...)):
data = file.read()
return {'name': file.name, 'len': len(data)}
@api.post("/upload-list")
def upload_many(request, files: List[UploadedFile] = File(...)):
return [f.name for f in files]
Response Schema
Request Body 함수에서 서버동작에 따른 메세지 결과를 각각 정의할 수 있습니다.
from ninja.responses import codes_4xx, codes_2xx
@api.post('/login', response={200: Token, codes_4xx: Message})
def login(request, payload: Auth):
if `auth_not_valid`:
return 401, {'message': 'Unauthorized'}
if `negative_balance`:
return 402, {'message': 'Insufficient balance amount. Please proceed to a payment page.'}
return 200, {'token': xxx, ...}
Schema 정의하는 클래스는 다음과 같은 방식으로도 사용할 수 있습니다.
class UserSchema(ModelSchema):
class Config:
model = User
model_fields = "__all__"
class UserSchema(ModelSchema):
class Config:
model = User
model_exclude = ['password', 'last_login', 'user_permissions']
Schema 클래스를 상속 할 수 있습니다. 상속을 받는 자손 클래스에서는 필드와 주석의 내용을 추가할 수 있습니다
class GroupSchema(ModelSchema):
class Config:
model = Group
model_fields = ['id', 'name']
class UserSchema(ModelSchema):
groups: List[GroupSchema] = []
class Config:
model = User
model_fields = ['id', 'username', 'first_name', 'last_name']
Schema 클래스의 API End point 중, 사용자 함수를 사용하는 End Point 를 추가할 수 있습니다. 아래의 예시는
def to_camel(string: str) -> str:
return ''.join(word.capitalize() for word in string.split('_'))
class CamelModelSchema(Schema):
str_field_name: str
float_field_name: float
class Config(Schema.Config):
alias_generator = to_camel
클래스 형식과 별개로, 함수 형태로도 활용할 수 있습니다. .update_forward_refs()
메서드는 객체 내부에 ForeignKey
를 사용하는 객체가 있는 경우에 적용 합니다. Create Schema 에 대한 보다 자세한 내용은 링크를 참고 합니다.
UserSchema = create_schema(
User,
name='UserSchema', # !!! this is important for update_forward_refs()
fields=['id', 'username']
custom_fields=[
('manager', 'UserSchema', None),
]
)
UserSchema.update_forward_refs()
Ninja Auth
Django 에서 React 와 보안을 위해 사용하는 방법중에 PyJWT 를 활용한 Token 을 검증하는 방법부터, SNS 소셜 미디어를 활용한 로그인 방법까지 알아 보도록 하겠습니다.
로그인 관련 개념 내용들은 쉽게 알아보는 서버 인증 2편(Access Token + Refresh Token) 및 DRF JWT 인증방식 로그인, 회원가입 내용을 참고합니다
PyJWT
아래 코드는 {"some":"payload"}
객체를 HS256
로 암화화된 방법을 사용해서 전달하는 내용 입니다.
암호를 생성하고, 해석하는데 필요한 Key 객체로써, 아래의 예시에서는 key
데이터를 사용하여 확인 합니다.
import jwt
key = "secret"
encoded = jwt.encode({"name": "payload", "password":"secret1234"}, key, algorithm="HS256")
print(encoded)
#eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg
jwt.decode(encoded, key, algorithms="HS256")
#{'some': 'payload'}
Django Ninja
Reddit 에 설명한 예시 내용을 이해 해보겠습니다.