Django ile Hızlı ve Güçlü RESTful API Geliştirme
Django'nun bir çok sorunu kolayca halletmemizi sağlayan/yardımcı olan bir çok modülü var. Kolayca RESTful API'ler inşa etmek isteyenler için de "Django REST Framework" bunlardan biri. Başlamadan önce, RESTful API hakkında bilgisi olmayan, meraktan gelenler buraya tıklayarak ön bilgi edinebilirler.
Kurulum
Django'nun hali hazırda kurulu olduğunu ve virtual environment
içinde olduğunuzu varsayıyorum. Hemen pip3
ile yükleyelim.
pip3 install djangorestframework
Başlatılmış bir proje ve uygulama yoksa, aşağıdaki gibi oluşturabilirsiniz. Eğer hali hazırda varolan bir proje içinde kullanmak istiyorsanız o da mümkün. Şuan çalıştığınız uygulama içinde de kullanabilirsiniz tabii, ancak API için ayrı bir uygulama başlatmanızı öneririm.
django-admin startproject rest_apisi_olan_proje cd rest_apisi_olan_proje python manage.py startapp api
Oluşturduğunuz uygulamayı proje içinde kullanabilmek için settings.py
içinde tanımlı olması gerekiyor.
INSTALLED_APPS = ( # ... "rest_framework", "api")Ayrı bir uygulama oluşturmamış olasanız bile
rest_framework
kısmını eklemelisiniz. Son olarak değişiklikleri veritabanına uygulayalım.python3 manage.py makemigrations python3 manage.py migrate
Kullanım
Şimdi, az önce oluşturduğunuz api
uygulaması içinde serializers.py
dosyası oluşturup, içinde API ile erişim sağlanacak modelleri serialize edecek nesneleri hazırlayın. Bu nesneler ModelSerializer
sınıfından miras almak zorundalar ve meta sınıf içinde model ismi ile serileştirilecek alanların tanımlı olması zorunlu.
from app.models import Article from rest_framework import serializers class ArticleSerializer(serializers.ModelSerializer): class Meta: model = Article fields = ("id", "title", "body")
Şimdi yine api
uygulaması içindeki views.py
dosyasına, aşağıdaki gibi API ile yapılabilmesini istediğimiz fonksiyonları ekleyelim.
from django.http import Http404 from app.models import Article from api.serializers import ArticleSerializer from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status class ArticleList(APIView): """ Kayıtlı makaleleri listele ya da yenisini ekle. """ def get(self, request, format=None): articles = Article.objects.all() serializer = ArticleSerializer(articles, many=True) return Response(serializer.data) def post(self, request, format=None): serializer = ArticleSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class ArticleSingle(APIView): """ Tekil makale getir, düzenle ya da sil. """ def get_object(self, pk): try: return Article.objects.get(pk=pk) except Article.DoesNotExist: raise Http404 def get(self, request, pk, format=None): article = self.get_object(pk) article = ArticleSerializer(article) return Response(article.data) def put(self, request, pk, format=None): article = self.get_object(pk) serializer = ArticleSerializer(article, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, pk, format=None): article = self.get_object(pk) article.delete() return Response(status=status.HTTP_204_NO_CONTENT)
Burada APIView sınıflarının içlerinde bulunan fonksiyonlar request tiplerini gösteriyor. Daha önce karşılaşmayanlar için en çok kullanılan dört request tipi; GET
listeleme, POST
ekleme, PUT
düzenleme ve DELETE
silme isteği olduğunu belirtiyor. Tümünü incelemek isterseniz; Request methods.
Şimdi hazırladığınız APIView'lar için URL belirleme zamanı. Ben /api/articles
veya /api/articles/1
gibi erişilmesini istediğim için aşağıdaki gibi yaptım. Siz dilediğiniz ismi verebilirsiniz, APIView sınıflarına verdiğiniz ismin bir önemi yok. Oluşturduğumuz api
modülüne urls.py
dosyasını ekleyip kaydedelim.
from django.conf.urls import url from api import views urlpatterns = [ url(r"articles$", views.ArticleList.as_view(), name="api-article-list"), url(r"articles/(?P<pk>[0-9]+)$", views.ArticleSingle.as_view(), name="api-article-single"), ]
Tabi yukarıda adresler için /api
ön eki yok. Onu, bu adresleri projenin adreslerine dahil ederken yapacağız. Üzerinde çalıştığınız projenin (ana projenin/uygulamanın) içindeki urls.py
dosyasına girin ve şuna benzer bir şekilde yukarıda tanımladığımız adresleri dahil edin.
from django.conf.urls import url, include from django.contrib import admin urlpatterns = [ url(r"^admin/", admin.site.urls), url(r"^api/", include("api.urls")), ]
Buraya kadar bir problem yoksa her şey tamam demektir. Her zamanki gibi debug serverını çalıştırıp sonucu gözlelerinizle görebilirsiniz.
python3 manage.py runserver
Yayınladığınız API'ın adresi http://127.0.0.1:8000/api/articles
ya da buna benzer bir şey olacaktır.
Belirlediğiniz API adreslerine tarayıcıdan girdiğinizde hem o API View hakkında bilgi bulabilecek hem de altta test etmek için bir bölüm göreceksiniz. Bunun haricinde RESTClient gibi eklentilerle de test edebilirsiniz.
Birim Testi
Şimdi, API çalışıyor mu diye unit test ile teyit edelim. Önce, test için kullanılmak üzere uygulama içine bir kaç tane deneme kaydı ekleyin -ki buradaki örnekte Article- ve aşağıdaki komut ile bu kayıtlar için fixture oluşturun.
python3 manage.py dumpdata app --format=json --indent=4 > app/fixtures/articles.json
Tabii bu komuttaki app
olan kısımları kendi uygulama isminiz ile değiştirmeyi unutmayın.
Ardından, oluşturduğunuz api
uygulaması içine tests.py
dosyası oluşturup içine aşağıdaki gibi ya da buna benzer bir test yazın. Konumuz birim testi değil ancak testlerin django-rest-framework ile beraber kullanımından bahsetmek istedim.
from django.test import TestCase from django.core.urlresolvers import reverse from rest_framework import status from rest_framework.test import APIClient from app.models import Article class ArticleTestCase(TestCase): fixtures = ["articles.json"] def setUp(self): self.client = APIClient() def test_article_list_get(self): response = self.client.get(reverse("api-articles-list")) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_article_list_post(self): data = { "title": "Bu bir test başlığıdır.", "message": "Bu bir test içeriğidir.", } response = self.client.post(reverse("api-articles-list"), data, format="json") self.assertEqual(response.status_code, status.HTTP_201_CREATED) def test_article_single_get(self): article = Article.objects.first() response = self.client.get(reverse("api-article-single", kwargs={"pk": article.pk})) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_article_single_delete(self): article = Article.objects.first() response = self.client.delete(reverse("api-article-single", kwargs={"pk": article.pk}))
Son olarak testi başlatıyoruz.
python3 manage.py test api
Eğer aşağıdaki gibi bir ekranla karşılaşırsanız her şey yolunda demektir. Aksi halde karşılaşılan hataları görebilirsiniz.
Merak ettiğiniz bir şey olursa yorumlar bölümünden sormaktan çekinmeyin. :)
Kolay gelsin...