Asosiy kontentga o‘tish

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.

api django python

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#

Terminal
uv add drf-spectacular
Python
# 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,
}
Python
# 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:

Python
# 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:

Python
# 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:

Python
# 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:

Python
# 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.

8 daqiqa 1005 marta o‘qildi