Giới thiệu
REST API (Representational State Transfer API) là một phần thiết yếu trong việc xây dựng các ứng dụng phần mềm và dịch vụ, giúp tối ưu hóa tương tác giữa client và server một cách hiệu quả. REST là một phong cách kiến trúc phần mềm cho phép truy xuất và truyền tải yêu cầu của người dùng từ phía client và thông tin được xử lý từ phía server dưới định dạng JSON hoặc một số định dạng khác.
Nguyên tắc hoạt động của REST API
Các yêu cầu từ client được thực hiện thông qua Giao thức Truyền tải Siêu văn bản (HTTP) với các phương thức HTTP như:
- GET: Lấy dữ liệu từ server.
- POST: Gửi và xuất bản thông tin lên server.
- PUT: Cập nhật thông tin trên server.
- PATCH: Chỉnh sửa một phần tài nguyên hiện có.
- DELETE: Xóa thông tin từ server.
REST APIs tuân theo các nguyên tắc:
- Kiến trúc client-server.
- Stateless (không duy trì trạng thái).
- Dữ liệu có thể được cache.
- Đảm bảo tính đồng nhất giữa các hệ thống.
- Kiến trúc phân lớp.
REST API được sử dụng phổ biến trong phát triển ứng dụng di động và web vì các ứng dụng di động có thể truy cập chúng ở chế độ nền, trong khi các ứng dụng web có thể hưởng lợi từ nội dung động mà không cần phải tải lại trang. Hơn nữa, các tích hợp bên thứ ba như cổng thanh toán và microservices cũng sử dụng REST APIs để tương tác với các dịch vụ khác trong hệ thống lớn hơn.
Django REST Framework là gì?
Django cung cấp nhiều tùy chọn để xây dựng REST APIs, và một trong số đó là Django REST Framework (DRF) - một bộ công cụ mạnh mẽ và linh hoạt cho việc xây dựng các giao diện lập trình ứng dụng web (API). Gói OAuth của Django REST Framework hỗ trợ cả OAuth1 và OAuth2, hỗ trợ serialization cho cả nguồn dữ liệu ORM và không phải ORM, tài liệu phong phú và nhiều tính năng tùy biến khác.
Trong hướng dẫn này, chúng ta sẽ tìm hiểu cách xây dựng một RESTful API bằng cách sử dụng Django MongoDB Backend chính thức và nhấn mạnh các tính năng có sẵn.
Điều kiện tiên quyết
- Một cụm MongoDB Atlas với dataset
sample_geospatialmặc định - tìm hiểu cách tạo một deployment. - Tải xuống Python 3.10 hoặc phiên bản mới hơn.
Cài đặt và cấu hình
Thiết lập môi trường ảo
bash
python -m venv venv
source venv/bin/activate
Cài đặt Django MongoDB Backend và DRF
bash
pip install django-mongodb-backend djangorestframework
Cấu hình kết nối MongoDB
Cấu hình kết nối MongoDB trong file settings.py của dự án Django.
Cấu trúc dự án
Sau khi tạo môi trường ảo, hãy tạo một dự án Django với mẫu dự án Django MongoDB Backend. Mẫu này tương tự như mẫu dự án Django mặc định nhưng bao gồm các migrations đặc thù của MongoDB và sửa đổi file settings.py để cấu hình Django sử dụng ObjectId làm khóa chính cho mỗi mô hình.
Cấu trúc thư mục cuối cùng sẽ như sau:
myproject/
│
├── shipwrecks_api/
│ ├── migrations/
│ ├── models.py
│ ├── serializers.py
│ ├── views.py
│ └── urls.py
└── manage.py
Tổng quan về mô hình MVC của Django
Kiến trúc dự án Django theo mô hình Model View Controller (MVC) nhưng với một biến thể, nơi bạn có Models, Templates và Views (MTV). Mô hình trong Django bao gồm:
- Mô hình: Là lớp dữ liệu, định nghĩa cách mà dữ liệu được cấu trúc, kiểm tra tính hợp lệ, và xử lý tương tác với cơ sở dữ liệu MongoDB.
- View: Mô tả dữ liệu được trình bày cho người dùng, không nhất thiết phải là cách dữ liệu nhìn, mà là dữ liệu nào được trình bày.
- Template: Là lớp trình bày, bao gồm các file HTML định nghĩa cách mà dữ liệu sẽ xuất hiện với người dùng.
Định nghĩa mô hình
Với Django MongoDB Backend, trường _id của MongoDB được ánh xạ thành trường id truyền thống của Django, nghĩa là bạn sẽ không có cả _id và id cùng lúc. Điều này được thực hiện thông qua dòng mã DEFAULT_AUTO_FIELD = 'django_mongodb_backend.fields.ObjectIdAutoField' trong file settings.py.
Mô hình của chúng ta sẽ như sau:
python
# models.py
from django.db import models
from django_mongodb_backend.fields import ArrayField
from django_mongodb_backend.managers import MongoManager
class ShipwreckFeature(models.Model):
recrd = models.CharField(max_length=200, blank=True)
vesslterms = models.CharField(max_length=200, blank=True)
feature_type = models.CharField(max_length=200, blank=True)
chart = models.CharField(max_length=200, blank=True)
latdec = models.FloatField(null=True, blank=True)
londec = models.FloatField(null=True, blank=True)
gp_quality = models.CharField(max_length=200, blank=True)
depth = models.CharField(max_length=200, blank=True)
sounding_type = models.CharField(max_length=200, blank=True)
history = models.TextField(blank=True)
quasou = models.CharField(max_length=200, blank=True)
watlev = models.CharField(max_length=200, blank=True)
coordinates = ArrayField(
base_field=models.FloatField(), null=True, blank=True
)
objects = MongoManager()
class Meta:
db_table = "shipwrecks_api"
managed = False
def __str__(self):
return f"{self.feature_type} tại ({self.latdec}, {self.londec})"
Serializers
Giới thiệu về serializers trong DRF
Serializers cho phép dữ liệu phức tạp, như queryset và model instances, được chuyển đổi thành các kiểu dữ liệu Python bản địa có thể dễ dàng được chuyển đổi thành JSON, XML hoặc các loại nội dung khác. Serializers cũng cung cấp khả năng deserialization, cho phép dữ liệu đã phân tích được chuyển đổi lại thành các loại phức tạp, sau khi đã xác thực dữ liệu đầu vào.
Trong lớp serializer dưới đây, chúng ta sử dụng hai trường serializer:
- SerializerMethodField: Là trường chỉ đọc, giá trị của nó được lấy từ một phương thức trên lớp serializer mà nó được gắn vào.
- HyperlinkedIdentityField: Có thể được áp dụng như một mối quan hệ danh tính, chẳng hạn như trường
urltrong HyperlinkedModelSerializer.
Tạo serializers
python
# serializers.py
from rest_framework import serializers
from .models import ShipwreckFeature
class ShipwreckFeatureSerializer(serializers.ModelSerializer):
id = serializers.SerializerMethodField(read_only=True)
url = serializers.HyperlinkedIdentityField(
view_name='shipwreck-detail'
)
def get_id(self, obj):
return str(obj.pk) if obj.pk else None
class Meta:
model = ShipwreckFeature
fields = [
'id', 'url', 'recrd', 'vesslterms', 'feature_type',
'chart', 'latdec', 'londec',
'gp_quality', 'depth', 'sounding_type',
'history', 'quasou', 'watlev',
'coordinates'
]
read_only_fields = ['id']
Views và cấu hình URL
Hãy tạo các view dựa trên hàm để hiển thị dữ liệu về các vụ đắm tàu.
python
# views.py
from rest_framework import viewsets, filters, permissions
from rest_framework.response import Response
from rest_framework import status
from django.shortcuts import get_object_or_404
from bson import ObjectId
from bson.errors import InvalidId
from .models import ShipwreckFeature
from .serializers import ShipwreckFeatureSerializer
from django_filters.rest_framework import DjangoFilterBackend
class ShipwreckFeatureViewSet(viewsets.ModelViewSet):
queryset = ShipwreckFeature.objects.all()
serializer_class = ShipwreckFeatureSerializer
permission_classes = [permissions.AllowAny]
filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
lookup_field = 'pk'
filterset_fields = ['recrd', 'vesslterms', 'feature_type', 'latdec', 'londec']
ordering_fields = ['latdec', 'londec']
ordering = ['latdec']
def get_object(self):
lookup_value = self.kwargs[self.lookup_field]
try:
if not ObjectId.is_valid(lookup_value):
raise InvalidId("Định dạng ObjectId không hợp lệ")
object_id = ObjectId(lookup_value)
except (InvalidId, ValueError):
from django.http import Http404
raise Http404("Định dạng ObjectId không hợp lệ")
queryset = self.filter_queryset(self.get_queryset())
obj = get_object_or_404(queryset, pk=object_id)
self.check_object_permissions(self.request, obj)
return obj
def destroy(self, request, *args, **kwargs):
try:
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
except Exception as e:
return Response({'error': f'Không thể xóa vụ đắm tàu: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
Cấu hình URL để ánh xạ các view trong shipwrecks_api
python
# urls.py - shipwrecks_api
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ShipwreckFeatureViewSet
router = DefaultRouter()
router.register(r'shipwrecks', ShipwreckFeatureViewSet, basename='shipwreck')
urlpatterns = [
path('', include(router.urls)),
]
Sử dụng shell Python để tạo đối tượng
python
sw1 = ShipwreckFeature.objects.create(
recrd="R001",
vesslterms="RMS Titanic",
feature_type="Wrecks - Submerged, not dangerous",
chart="US,U1,graph,DNC H140984",
latdec=10.123456,
londec=-80.654321,
gp_quality="A",
depth="3840 meters",
sounding_type="approximate",
history="RMS Titanic chìm vào ngày 15 tháng 4 năm 1912, sau khi va phải một tảng băng.",
quasou="depth known",
watlev="always under water/submerged",
coordinates=[-80.654321, 10.123456]
)
Các thao tác CRUD
Các phương thức CRUD — CREATE, GET/RETRIEVE, UPDATE và DELETE — có thể được thực hiện thông qua API web DRF, Postman và shell Python. Ví dụ, để GET tất cả các vụ đắm tàu, bạn có thể truy cập vào http://127.0.0.1:8000/shipwrecks/.
Phân trang
Phân trang cho phép bạn điều chỉnh cách mà các tập kết quả lớn được chia thành các trang dữ liệu riêng biệt nhằm cải thiện khả năng đọc và hiệu suất. Để sử dụng lớp phân trang mặc định, thêm các dòng mã sau vào settings.py:
python
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20
}
Kiểm thử
python
from django.test import TestCase
from rest_framework.test import APITestCase
from rest_framework import status
from django.urls import reverse
from .models import ShipwreckFeature
class ShipwreckFeatureModelTest(TestCase):
def setUp(self):
self.shipwreck = ShipwreckFeature.objects.create(
recrd="R001",
vesslterms="test_vessel",
feature_type="wreck",
chart="test_chart",
latdec=40.7128,
londec=-74.0060,
history="Test shipwreck for testing",
coordinates=[-74.0060, 40.7128]
)
def test_shipwreck_creation(self):
self.assertEqual(self.shipwreck.recrd, "R001")
class ShipwreckFeatureAPITest(APITestCase):
def setUp(self):
self.shipwreck = ShipwreckFeature.objects.create(
recrd="R002",
vesslterms="api_test_vessel",
feature_type="wreck",
latdec=41.0,
londec=-75.0,
history="API test shipwreck"
)
self.list_url = reverse('shipwreck-list')
def test_get_shipwreck_list(self):
response = self.client.get(self.list_url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
Tài liệu
Sử dụng các công cụ như Swagger UI, Postman, OpenAPI Generator để tài liệu hóa các điểm cuối API. Để cài đặt Swagger với Django:
bash
pip install drf-spectacular
Thêm 'drf_spectacular' vào INSTALLED_APPS trong settings.py.
Kết luận
Trong hướng dẫn này, chúng ta đã tìm hiểu về kiến trúc REST API, phương thức HTTP, Django REST Framework, cách cài đặt và cấu hình dự án API, định nghĩa mô hình, URL, views, kiểm thử và tài liệu hóa API bằng Swagger.
Bạn đã có những kiến thức cần thiết để tạo một REST API với Django REST Framework và Django MongoDB Backend. Hãy thử nghiệm và để lại phản hồi về trải nghiệm của bạn nhé!