Maqolalar 8 daqiqa 1005 ko‘rish
DRF'da avtomatik Swagger: hujjat kodning o'zidan tug'iladi
«Qanday endpoint'lar bor, nima yuboraman, nima keladi?» — frontend jamoasining abadiy savoli. drf-spectacular bilan API hujjati koddan avtomatik yasaladi va kod o'zgarsa hujjat ham o'zi yangilanadi. Netflix-uslub API misolida sozlaymiz.
Mundarija
API yozayotgan odamning ishi endpoint bilan tugamaydi — uni kimdir ishlatishi kerak: mobil jamoa, frontendchi, ba'zan olti oydan keyingi o'zingiz. Va shu yerda abadiy savollar boshlanadi: qanday endpoint'lar bor, qaysi maydonlar majburiy, javob qanday ko'rinishda keladi. Buni qo'lda yozilgan hujjat bilan yechish mumkin, lekin qo'lda yozilgan hujjatning taqdiri ma'lum — u ikkinchi haftadayoq koddan orqada qoladi.
Netflix-uslub API loyihamda boshqa yo'lni tanlaganman va o'shandan beri hamma DRF loyihada shu turadi: hujjat kodning o'zidan yasaladi. Serializer'lar, view'lar, permission'lar allaqachon hamma ma'lumotni o'z ichida saqlaydi — uni chiroyli sahifaga aylantirib beradigan tool esa drf-spectacular.
Sozlash: uch qadam#
uv add drf-spectacular
# config/settings.py
INSTALLED_APPS = [
# ...
"rest_framework",
"drf_spectacular",
]
REST_FRAMEWORK = {
# DRF'ga sxemani kim yasashini aytamiz
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
}
SPECTACULAR_SETTINGS = {
"TITLE": "Movies API",
"DESCRIPTION": "Video-kontent katalogi: filmlar, janrlar, reytinglar.",
"VERSION": "1.0.0",
# /api/schema/ endpoint'ining o'zi hujjatdagi endpoint'lar ro'yxatida chiqmasin
"SERVE_INCLUDE_SCHEMA": False,
}
# config/urls.py
from django.urls import path
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
urlpatterns = [
# ...
# xom sxema (OpenAPI JSON/YAML) — tool'lar shuni o'qiydi
path("api/schema/", SpectacularAPIView.as_view(), name="schema"),
# odamlar uchun interaktiv sahifa
path("api/docs/", SpectacularSwaggerView.as_view(url_name="schema")),
]
Shu uch qadam bo'ldi. Brauzerda /api/docs/ ni oching — barcha
endpoint'laringiz, maydonlari va tiplari bilan ro'yxat bo'lib turibdi,
har birini "Try it out" tugmasi bilan shu yerning o'zida sinab ko'rsa
bo'ladi. Postman kolleksiyasini qo'lda yig'ib yurish shart emas.
Swagger sahifasi tashqi CDN'dan yuklanadi
Standart holatda /api/docs/ sahifasi Swagger UI fayllarini
cdn.jsdelivr.net dan @latest versiyada oladi. Ya'ni sahifaning ishlashi
begona serverga va har safar eng so'nggi relizga bog'liq, internetsiz
muhitda esa u ochilmaydi. Fayllarni loyihaning o'zidan berish uchun
uv add "drf-spectacular[sidecar]", INSTALLED_APPS ga
"drf_spectacular_sidecar" va SPECTACULAR_SETTINGS ga
"SWAGGER_UI_DIST": "SIDECAR", "SWAGGER_UI_FAVICON_HREF": "SIDECAR"
qo'shing — sahifa endi /static/ dan yuklanadi.
Hujjat sifatini kod sifati belgilaydi#
Muhim tushuncha: drf-spectacular hech narsani "o'ylab topmaydi", u faqat kodda borini ko'rsatadi. Demak hujjatni yaxshilamoqchi bo'lsangiz, kodning o'zini boyitishingiz kerak. Buning uch oddiy yo'li bor va ularning har biri hujjatni sezilarli yaxshilaydi.
Birinchisi — maydonlarga help_text. Uni model maydoniga yozish eng
foydalisi:
# apps/movies/models.py
from django.db import models
class Genre(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(unique=True)
class Movie(models.Model):
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
year = models.PositiveIntegerField(help_text="Chiqarilgan yili, masalan 2019")
rating = models.DecimalField(
max_digits=3, decimal_places=1, help_text="0 dan 10 gacha, bir xona aniqlikda"
)
genre = models.ForeignKey(Genre, on_delete=models.PROTECT, related_name="movies")
ModelSerializer bu matnni o'zi oladi: u Swagger sahifasida maydon tavsifi
bo'lib chiqadi va Django admin formasida ham ko'rinadi — bir mehnatga ikki
foyda. Serializer'da e'lon qilingan maydonga esa help_text shu yerning
o'zida yoziladi — u faqat API hujjatiga tushadi, admin'ga o'tmaydi:
# apps/movies/serializers.py
from rest_framework import serializers
from .models import Movie
class MovieSerializer(serializers.ModelSerializer):
# janr raqam emas, tushunarli slug bo'lib chiqsin: "drama"
genre = serializers.SlugRelatedField(
slug_field="slug", read_only=True, help_text="Janr: drama, komediya..."
)
class Meta:
model = Movie
fields = ["id", "title", "year", "rating", "genre"]
Ikkinchisi — alohida holatlarni extend_schema bilan izohlash. Standart
CRUD o'zi tushunarli chiqadi, lekin maxsus action'larga izoh kerak bo'ladi:
# apps/movies/views.py
from drf_spectacular.utils import extend_schema
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
@extend_schema(
summary="Tavsiya etilgan filmlar",
description="Foydalanuvchi reytinglariga qarab 10 ta film qaytaradi. "
"Ro'yxat har soatda qayta hisoblanadi.",
responses=MovieSerializer(many=True),
)
@action(detail=False)
def recommended(self, request): ...
Uchinchisi — docstring odatlari: view klassining docstring'i ham sxemaga tushadi. Ya'ni kod o'qigan hamkasbingiz uchun yozgan izohingiz frontend jamoasi uchun hujjat bo'lib ham xizmat qiladi.
Sxemani CI'da tekshiring
Sxema koddan yasalgani uchun uni buzish ham kod bilan bo'ladi — masalan
turli app'lardagi bir xil nomli ikkita serializer to'qnashsa, spectacular
ogohlantirish beradi. Tekshiruv buyrug'i:
python manage.py spectacular --validate --fail-on-warn --file /dev/null
— CI zanjiringizga shu qadamni qo'shib
qo'ysangiz, hujjat buzilgan holatda deploy o'tmaydi. --fail-on-warn
muhim: busiz buyruq ogohlantirishni ekranga chiqaradi-yu, baribir
0 kod bilan tugaydi va CI yashil qoladi — sinovda aynan shunday bo'ldi.
Kimga ochiq bo'lishi kerak?#
Bitta savolni ochiq muhokama qilgan ma'qul: hujjat sahifasi hammaga
ko'rinsinmi? Ochiq, ommaviy API bo'lsa — albatta. Ichki loyihada esa
/api/docs/ sahifasi API'ingizning to'liq xaritasi ekanini unutmang —
begona ko'z uchun bu qimmatli razvedka. Bunday holatda hujjatni faqat
xodimlarga (is_staff) ochamiz — SPECTACULAR_SETTINGS ga bitta qator:
# config/settings.py
SPECTACULAR_SETTINGS = {
# ...
# sxema ham, Swagger sahifasi ham faqat staff foydalanuvchilarga
"SERVE_PERMISSIONS": ["rest_framework.permissions.IsAdminUser"],
}
Sinovda anonim va oddiy foydalanuvchi /api/docs/ va /api/schema/ dan
403 oldi, staff esa 200. API endpoint'larining o'ziga bu sozlama
ta'sir qilmaydi. Xodim hujjatni brauzerda, /admin/ ga kirgan sessiyasi
bilan ochadi. Agar loyihada DEFAULT_AUTHENTICATION_CLASSES faqat JWT'dan
iborat bo'lsa, bu sessiyani hech kim tekshirmaydi va staff ham 401 oladi.
Unda yana bitta qator qo'shing:
"SERVE_AUTHENTICATION": ["rest_framework.authentication.SessionAuthentication"].
Nega faqat Swagger sahifasini staff_member_required bilan o'rab qo'yish
yetmaydi? Ikki sabab bor. Birinchidan, sahifa sxemani /api/schema/ dan
oladi — u ochiq qolsa, xarita baribir hammaga ochiq: sahifa shunchaki
uni chiroyli ko'rsatadigan qobiq. Ikkinchidan, himoyalangan yo'lni
urlpatterns += [...] bilan ro'yxat oxiriga qo'shsangiz, Django birinchi
mos kelgan yo'lni ishlatadi — yuqorida turgan himoyasiz api/docs/ ishlab
ketadi. Sinovda shunday qilinganda anonim foydalanuvchi sahifani 200 bilan
ochdi. SERVE_PERMISSIONS ikkala muammoni birdan yopadi.
Yakun#
Ikkita URL va bitta sozlama bloki evaziga API'ingiz o'zini o'zi hujjatlaydigan
bo'ldi: kod o'zgardi — hujjat o'zgardi, orada hech kim hech narsani qo'lda
yangilamaydi. Sifatni oshirish ham tanish ishlar orqali: help_text,
docstring, extend_schema. Hujjat endi alohida yuk emas, kod yozish
odatining bir qismi.
Keyingi — juftlikning ikkinchi qismi: filtrlash va pagination — ro'yxat endpoint'ini «hammasini qaytaradigan»dan «keraklisini qaytaradigan»ga aylantirish.