Cách tạo trình rút ngắn URL với Django và GraphQL
GraphQL là một tiêu chuẩn API do Facebook tạo ra và có nguồn mở để thay thế cho các API REST . Trái ngược với các API REST, GraphQL sử dụng một hệ thống được định kiểu để xác định cấu trúc dữ liệu của nó, trong đó tất cả thông tin được gửi và nhận phải tuân theo một schemas được định nghĩa . Nó cũng hiển thị một điểm cuối duy nhất cho tất cả giao tiếp thay vì nhiều URL cho các tài nguyên khác nhau và giải quyết vấn đề tìm nạp quá mức bằng cách chỉ trả lại dữ liệu được khách hàng yêu cầu, do đó tạo ra các phản hồi nhỏ hơn và ngắn gọn hơn. Trong hướng dẫn này, bạn sẽ tạo phần backend cho trình rút gọn URL — một dịch vụ lấy bất kỳ URL nào và tạo ra version ngắn hơn, dễ đọc hơn — trong khi đi sâu vào các khái niệm GraphQL, như truy vấn và đột biến , và các công cụ, như giao diện GraphiQL . Bạn có thể đã sử dụng các dịch vụ như vậy trước đây, như bit.ly
Vì GraphQL là một công nghệ bất khả tri ngôn ngữ nên nó được triển khai trên nhiều ngôn ngữ và khuôn khổ khác nhau. Ở đây, bạn sẽ sử dụng ngôn ngữ lập trình Python cho mục đích chung, khuôn khổ web Django và thư viện Graphene-Django làm triển khai GraphQL Python với các tích hợp cụ thể cho Django.
Yêu cầu
Để tiếp tục với hướng dẫn này, bạn cần cài đặt Python version 3.5 trở lên trên máy phát triển của bạn . Để cài đặt Python, hãy làm theo hướng dẫn của ta về Cách cài đặt và cài đặt môi trường lập trình local cho Python 3 cho hệ điều hành của bạn. Đảm bảo cũng tạo và bắt đầu một môi trường ảo ; để làm theo hướng dẫn của hướng dẫn này, bạn có thể đặt tên folder dự án của bạn
shorty
.Bạn cần có kiến thức sơ cấp về Django nhưng không bắt buộc. Nếu bạn tò mò, bạn có thể theo dõi loạt bài Phát triển Django này được tạo ra bởi cộng đồng DigitalOcean.
Bước 1 - Cài đặt Dự án Django
Trong bước này, bạn sẽ cài đặt tất cả các công cụ cần thiết cho ứng dụng và cài đặt dự án Django của bạn .
Khi bạn đã tạo folder dự án và khởi động môi trường ảo của bạn , như đã đề cập trong yêu cầu , hãy cài đặt các gói cần thiết bằng pip
, trình quản lý gói Python. Hướng dẫn này sẽ cài đặt Django version 2.1.7 và Graphene-Django version 2.2.0 trở lên:
- pip install "django==2.1.7" "graphene-django>==2.2.0"
Đến đây bạn có tất cả các công cụ cần thiết trong đai công cụ của bạn . Tiếp theo, bạn sẽ tạo một dự án Django bằng lệnh django-admin
. Dự án là bản soạn sẵn Django mặc định — một tập hợp các folder và file với mọi thứ cần thiết để bắt đầu phát triển ứng dụng web. Trong trường hợp này, bạn sẽ gọi dự án của bạn shorty
và tạo nó bên trong folder hiện tại của bạn bằng cách chỉ định .
cuối cùng:
- django-admin startproject shorty .
Sau khi tạo dự án của bạn , bạn sẽ chạy quá trình di chuyển Django . Các file này chứa mã Python do Django tạo ra và chịu trách nhiệm thay đổi cấu trúc của ứng dụng theo các mô hình Django. Ví dụ: các thay đổi có thể bao gồm việc tạo một bảng. Theo mặc định, Django đi kèm với tập hợp di chuyển riêng chịu trách nhiệm cho các hệ thống con như Xác thực Django , vì vậy cần thực thi chúng bằng lệnh sau:
- python manage.py migrate
Lệnh này sử dụng trình thông dịch Python để gọi một tập lệnh Django có tên là manage.py
, chịu trách nhiệm quản lý các khía cạnh khác nhau của dự án của bạn, như tạo ứng dụng hoặc chạy di chuyển.
Điều này sẽ cho kết quả tương tự như sau:
OutputOperations to perform: Apply all migrations: admin, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying sessions.0001_initial... OK
Khi database của Django đã sẵn sàng, hãy khởi động server phát triển local của nó:
- python manage.py runserver
Điều này sẽ cho:
OutputPerforming system checks... System check identified no issues (0 silenced). March 18, 2020 - 15:46:15 Django version 2.1.7, using settings 'shorty.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
Lệnh này sẽ xóa dấu nhắc trong terminal của bạn và khởi động server .
Truy cập trang http://127.0.0.1:8000
trong trình duyệt local của bạn. Bạn sẽ thấy trang này:
Để dừng server và quay lại terminal của bạn, hãy nhấn CTRL+C
Khi nào bạn cần truy cập trình duyệt, hãy đảm bảo lệnh trước đó đang chạy.
Tiếp theo, bạn sẽ hoàn thành bước này bằng cách bật thư viện Django-Graphene trong dự án. Django có khái niệm về app
, một ứng dụng web với một trách nhiệm cụ thể. Một dự án bao gồm một hoặc nhiều ứng dụng. Bây giờ, hãy mở file shorty /settings.py
trong editor mà bạn chọn. Hướng dẫn này sẽ sử dụng vim
:
- vim shorty/settings.py
Tệp settings.py
quản lý tất cả các cài đặt trong dự án của bạn. Bên trong nó, tìm kiếm mục nhập INSTALLED_APPS
và thêm dòng 'graphene_django'
:
... INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'graphene_django', ] ...
Phần bổ sung này cho Django biết rằng bạn sẽ sử dụng một ứng dụng có tên graphene_django
, mà bạn đã cài đặt ở Bước 1.
Ở cuối file , hãy thêm biến sau:
... GRAPHENE = { 'SCHEMA': 'shorty.schema.schema', }
Biến cuối cùng này trỏ đến Lược đồ chính của bạn, mà bạn sẽ tạo sau này. Trong GraphQL, một Lược đồ chứa tất cả các kiểu đối tượng, chẳng hạn như Tài nguyên, Truy vấn và Đột biến. Hãy coi đó là tài liệu đại diện cho tất cả dữ liệu và chức năng có sẵn trong hệ thống của bạn.
Sau khi sửa đổi, hãy lưu file .
Đến đây bạn đã cấu hình dự án Django. Trong bước tiếp theo, bạn sẽ tạo một ứng dụng Django và các Mô hình của nó.
Bước 2 - Cài đặt Mô hình và Ứng dụng Django
Một nền tảng Django thường bao gồm một dự án và nhiều ứng dụng hoặc ứng dụng . Một ứng dụng mô tả một tập hợp các tính năng bên trong một dự án và nếu được thiết kế tốt, được dùng lại trên các dự án Django.
Trong bước này, bạn sẽ tạo một ứng dụng có tên là shortener
, chịu trách nhiệm về tính năng rút ngắn URL thực tế. Để tạo khung cơ bản của nó, hãy nhập lệnh tiếp theo trong terminal của bạn:
- python manage.py startapp shortener
Ở đây, bạn đã sử dụng các tham số startapp app_name
, hướng dẫn manage.py
để tạo một ứng dụng có tên là shortener
.
Để hoàn tất quá trình tạo ứng dụng, hãy mở file shorty /settings.py
- vim shorty/settings.py
Thêm tên của ứng dụng vào cùng một mục nhập INSTALLED_APPS
mà bạn đã sửa đổi trước đó:
... INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'graphene_django' 'shortener', ] ...
Lưu và đóng file .
Với trình shortener
của bạn được thêm vào shorty /settings.py
, bạn có thể chuyển sang tạo các mô hình cho dự án của bạn . Mô hình là một trong những tính năng chính trong Django. Chúng được sử dụng để đại diện cho database theo cách “Pythonic”, cho phép bạn quản lý, truy vấn và lưu trữ dữ liệu bằng mã Python.
Trước khi mở file models.py
để biết các thay đổi, hướng dẫn này sẽ cung cấp tổng quan về những thay đổi bạn sẽ thực hiện.
Tệp mô hình của bạn— shortener/models.py
—sẽ chứa nội dung sau khi bạn đã thay thế mã hiện tại:
from hashlib import md5 from django.db import models
Tại đây bạn sẽ nhập các gói cần thiết theo mã của bạn. Bạn sẽ thêm dòng from hashlib import md5
ở trên cùng để nhập thư viện chuẩn Python sẽ được sử dụng để tạo hàm băm của URL. Dòng from django.db import models
là một trình trợ giúp Django để tạo mô hình.
Cảnh báo: Hướng dẫn này đề cập đến hàm băm là kết quả của một hàm nhận đầu vào và luôn trả về cùng một kết quả . Hướng dẫn này sẽ sử dụng hàm băm MD5 cho mục đích demo .
Lưu ý MD5 có các vấn đề va chạm và cần tránh trong quá trình production .
Tiếp theo, bạn sẽ thêm URL
có tên Model với các trường sau:
-
full_url
: URL được rút ngắn. -
url_hash
: một băm ngắn đại diện cho URL đầy đủ. -
clicks
: số lần URL ngắn được truy cập. -
created_at
: ngày và giờ URL được tạo.
... class URL(models.Model): full_url = models.URLField(unique=True) url_hash = models.URLField(unique=True) clicks = models.IntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True)
Bạn sẽ tạo url_hash
bằng cách áp dụng thuật toán băm MD5 cho trường full_url
và chỉ sử dụng 10 ký tự đầu tiên được trả về trong phương thức save()
của Model, được thực thi mỗi khi Django lưu mục nhập vào database . Ngoài ra, các trình rút gọn URL thường theo dõi số lần một liên kết được nhấp vào. Bạn sẽ đạt được điều này bằng cách gọi phương thức clicked()
khi user truy cập URL.
Các hoạt động được đề cập sẽ được thêm vào bên trong mô hình URL
của bạn với mã này:
... def clicked(self): self.clicks += 1 self.save() def save(self, *args, **kwargs): if not self.id: self.url_hash = md5(self.full_url.encode()).hexdigest()[:10] return super().save(*args, **kwargs)
Đến đây bạn đã xem lại mã, hãy mở file shortener/models.py
:
- vim shortener/models.py
Thay thế mã bằng nội dung sau:
from hashlib import md5 from django.db import models class URL(models.Model): full_url = models.URLField(unique=True) url_hash = models.URLField(unique=True) clicks = models.IntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True) def clicked(self): self.clicks += 1 self.save() def save(self, *args, **kwargs): if not self.id: self.url_hash = md5(self.full_url.encode()).hexdigest()[:10] return super().save(*args, **kwargs)
Đảm bảo lưu file .
Để áp dụng những thay đổi này trong database , bạn cần tạo di chuyển bằng cách chạy lệnh sau:
- python manage.py makemigrations
Điều này sẽ cung cấp cho bạn kết quả sau:
OutputMigrations for 'shortener': shortener/migrations/0001_initial.py - Create model URL
Sau đó thực hiện di chuyển:
- python manage.py migrate
Bạn sẽ thấy kết quả sau trong terminal của bạn :
OutputOperations to perform: Apply all migrations: admin, auth, contenttypes, sessions, shortener Running migrations: Applying shortener.0001_initial... OK
Đến đây bạn đã cài đặt các mô hình, trong bước tiếp theo, bạn sẽ tạo điểm cuối GraphQL và một Truy vấn.
Bước 3 - Tạo truy vấn
Kiến trúc REST cho thấy các tài nguyên khác nhau trong các điểm cuối khác nhau, mỗi điểm chứa một cấu trúc dữ liệu được xác định rõ. Ví dụ: bạn có thể tìm nạp danh sách user tại /api/users
, luôn mong đợi các trường giống nhau. Mặt khác, GraphQL có một điểm cuối duy nhất cho tất cả các tương tác và sử dụng Truy vấn để truy cập dữ liệu. Sự khác biệt chính — và có giá trị nhất — là bạn có thể sử dụng Truy vấn để truy xuất tất cả user của bạn trong một yêu cầu duy nhất.
Bắt đầu bằng cách tạo một Truy vấn để tìm nạp tất cả các URL. Bạn cần một số thứ:
- Một loại URL, được liên kết với mô hình đã xác định trước đó của bạn.
- Câu lệnh truy vấn có tên
urls
. - Một phương pháp để giải quyết Truy vấn của bạn, nghĩa là tìm nạp tất cả các URL từ database và trả chúng cho client .
Tạo một file mới có tên là shortener/schema.py
:
- vim shortener/schema.py
Bắt đầu bằng cách thêm các câu lệnh import
Python:
import graphene from graphene_django import DjangoObjectType from .models import URL
Dòng đầu tiên nhập thư viện graphene
chính, chứa các loại GraphQL cơ sở, như List
. DjangoObjectType
là công cụ trợ giúp để tạo định nghĩa Lược đồ từ bất kỳ mô hình Django nào và dòng thứ ba nhập mô hình URL
tạo trước đó của bạn.
Sau đó, tạo một loại GraphQL mới cho mô hình URL
bằng cách thêm các dòng sau:
... class URLType(DjangoObjectType): class Meta: model = URL
Cuối cùng, thêm các dòng này để tạo loại Truy vấn cho mô hình URL
:
... class Query(graphene.ObjectType): urls = graphene.List(URLType) def resolve_urls(self, info, **kwargs): return URL.objects.all()
Mã này tạo một lớp Query
với một trường có tên urls
, là danh sách URLType
được định nghĩa đó. Khi giải quyết Truy vấn thông qua phương thức quyết resolve_urls
, bạn trả về tất cả các URL được lưu trữ trong database .
Tệp shortener/schema.py
đầy đủ được hiển thị ở đây:
import graphene from graphene_django import DjangoObjectType from .models import URL class URLType(DjangoObjectType): class Meta: model = URL class Query(graphene.ObjectType): urls = graphene.List(URLType) def resolve_urls(self, info, **kwargs): return URL.objects.all()
Lưu và đóng file .
Tất cả các Truy vấn bây giờ phải được thêm vào Lược đồ chính. Hãy coi nó như một người nắm giữ mọi tài nguyên của bạn.
Tạo file mới trong đường dẫn shorty /schema.py
và mở file đó bằng editor :
- vim shorty/schema
Nhập các gói Python sau bằng cách thêm các dòng sau. Cái đầu tiên, như đã đề cập, chứa các loại GraphQL cơ bản. Dòng thứ hai nhập file Lược đồ đã tạo trước đó.
import graphene import shortener.schema
Tiếp theo, thêm lớp Query
chính. Nó sẽ giữ, thông qua kế thừa, tất cả các Truy vấn và các hoạt động trong tương lai được tạo:
... class Query(shortener.schema.Query, graphene.ObjectType): pass
Cuối cùng, tạo biến schema
:
... schema = graphene.Schema(query=Query)
Cài đặt SCHEMA
mà bạn đã xác định ở Bước 2 trỏ đến biến schema
mà bạn vừa tạo.
Tệp shorty /schema.py
đầy đủ được hiển thị ở đây:
import graphene import shortener.schema class Query(shortener.schema.Query, graphene.ObjectType): pass schema = graphene.Schema(query=Query)
Lưu và đóng file .
Tiếp theo, kích hoạt điểm cuối GraphQL và giao diện GraphiQL , là một giao diện web đồ họa được sử dụng để tương tác với hệ thống GraphQL.
Mở file shorty /urls.py
:
- vim shorty/urls.py
Vì mục đích học tập, hãy xóa nội dung file và lưu nó để bạn có thể bắt đầu lại từ đầu.
Các dòng đầu tiên bạn sẽ thêm là các câu lệnh nhập Python:
from django.urls import path from django.views.decorators.csrf import csrf_exempt from graphene_django.views import GraphQLView
Hàm path
được Django sử dụng để tạo một URL có thể truy cập được cho giao diện GraphiQL. Sau đó, bạn nhập csrf_exempt
, cho phép client gửi dữ liệu đến server . Có thể tìm thấy lời giải thích đầy đủ trong Tài liệu Graphene . Trong dòng cuối cùng, bạn đã nhập mã thực tế chịu trách nhiệm cho giao diện qua GraphQLView
.
Tiếp theo, tạo một biến có tên urlpatterns
.
... urlpatterns = [ path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True))), ]
Điều này sẽ kết hợp tất cả các mã cần thiết lại với nhau để làm cho giao diện GraphiQL có sẵn trong graphql/
path:
Tệp shortener/urls.py
đầy đủ được hiển thị ở đây:
from django.urls import path from django.views.decorators.csrf import csrf_exempt from graphene_django.views import GraphQLView urlpatterns = [ path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True))), ]
Lưu file và đóng nó lại.
Quay lại terminal, chạy lệnh python manage.py runserver
(nếu chưa chạy):
- python manage.py runserver
Mở trình duyệt web tại địa chỉ http://localhost:8000/graphql
. Bạn sẽ thấy màn hình này:
GraphiQL là một giao diện nơi bạn có thể chạy các câu lệnh GraphQL và xem kết quả. Một tính năng là phần Docs
ở trên cùng bên phải. Vì mọi thứ trong GraphQL đều được nhập, bạn sẽ nhận được tài liệu miễn phí về tất cả các Loại, Truy vấn, Đột biến, v.v.
Sau khi khám phá trang, hãy chèn Truy vấn đầu tiên của bạn vào vùng văn bản chính:
query { urls { id fullUrl urlHash clicks createdAt } }
Nội dung này cho thấy cách cấu trúc một Truy vấn GraphQL: Đầu tiên, bạn sử dụng query
từ khóa để cho server biết rằng bạn chỉ muốn lấy lại một số dữ liệu. Tiếp theo, bạn sử dụng trường urls
được xác định trong file shortener/schema.py
bên trong lớp Query
. Từ đó, bạn yêu cầu rõ ràng tất cả các trường được xác định trong mô hình URL
bằng cách sử dụng kiểu chữ hoa camel, là kiểu mặc định cho GraphQL.
Bây giờ, nhấp vào nút mũi tên phát ở trên cùng bên trái.
Bạn sẽ nhận được phản hồi sau, cho biết rằng bạn vẫn không có URL:
Output{ "data": { "urls": [] } }
Điều này cho thấy GraphQL đang hoạt động. Trong terminal của bạn, nhấn CTRL+C
để dừng server của bạn.
Bạn đã hoàn thành rất nhiều trong bước này, tạo điểm cuối GraphQL, tạo Truy vấn để tìm nạp tất cả các URL và kích hoạt giao diện GraphiQL. Bây giờ, bạn sẽ tạo Mutations để thay đổi database .
Bước 4 - Tạo đột biến
Phần lớn các ứng dụng có cách thay đổi trạng thái database bằng cách thêm, cập nhật hoặc xóa dữ liệu. Trong GraphQL, các hoạt động này được gọi là Mutations . Chúng trông giống như Truy vấn nhưng sử dụng đối số để gửi dữ liệu đến server .
Để tạo Biến đổi đầu tiên của bạn, hãy mở shortener/schema.py
:
- vim shortener/schema.py
Ở cuối file , hãy bắt đầu bằng cách thêm một lớp mới có tên là CreateURL
:
... class CreateURL(graphene.Mutation): url = graphene.Field(URLType)
Lớp này kế thừa trình trợ giúp graphene.Mutation
để có các khả năng của Đột biến GraphQL. Nó cũng có url
tên thuộc tính, xác định nội dung được server trả về sau khi hoàn thành Mutation. Trong trường hợp này, nó sẽ là cấu trúc dữ liệu URLType
.
Tiếp theo, thêm một lớp con có tên Arguments
vào lớp đã được xác định:
... class Arguments: full_url = graphene.String()
Điều này xác định dữ liệu nào sẽ được server chấp nhận. Ở đây, bạn đang mong đợi một tham số có tên là full_url
với nội dung String
:
Bây giờ, thêm các dòng sau để tạo phương thức mutate
:
... def mutate(self, info, full_url): url = URL(full_url=full_url) url.save()
Phương thức mutate
này thực hiện rất nhiều công việc bằng cách nhận dữ liệu từ client và lưu vào database . Cuối cùng, nó trả về chính lớp có chứa mục mới được tạo.
Cuối cùng, tạo một lớp Mutation
để chứa tất cả các Mutation cho ứng dụng của bạn bằng cách thêm các dòng sau:
... class Mutation(graphene.ObjectType): create_url = CreateURL.Field()
Lúc này, bạn sẽ chỉ có một đột biến có tên là create_url
.
Tệp shortener/schema.py
đầy đủ được hiển thị ở đây:
import graphene from graphene_django import DjangoObjectType from .models import URL class URLType(DjangoObjectType): class Meta: model = URL class Query(graphene.ObjectType): urls = graphene.List(URLType) def resolve_urls(self, info, **kwargs): return URL.objects.all() class CreateURL(graphene.Mutation): url = graphene.Field(URLType) class Arguments: full_url = graphene.String() def mutate(self, info, full_url): url = URL(full_url=full_url) url.save() return CreateURL(url=url) class Mutation(graphene.ObjectType): create_url = CreateURL.Field()
Đóng và lưu file .
Để hoàn tất việc thêm Mutation, hãy thay đổi file shorty /schema.py
:
- vim shorty/schema.py
Thay đổi file để bao gồm mã được đánh dấu sau:
import graphene import shortener.schema class Query(shortener.schema.Query, graphene.ObjectType): pass class Mutation(shortener.schema.Mutation, graphene.ObjectType): pass schema = graphene.Schema(query=Query, mutation=Mutation)
Lưu và đóng file . Nếu bạn không chạy server local , hãy khởi động nó:
- python manage.py runserver
Điều hướng đến http://localhost:8000/graphql
trong trình duyệt web . Thực thi Mutation đầu tiên của bạn trong giao diện web GraphiQL bằng cách chạy câu lệnh sau:
mutation { createUrl(fullUrl:"https://www.digitalocean.com/community") { url { id fullUrl urlHash clicks createdAt } } }
Bạn đã tạo Biến đổi với tên createURL
, đối số fullUrl
và dữ liệu bạn muốn trong phản hồi được xác định bên trong trường url
.
Đầu ra sẽ chứa thông tin URL bạn vừa tạo bên trong trường data
GraphQL, như được hiển thị ở đây:
Output{ "data": { "createUrl": { "url": { "id": "1", "fullUrl": "https://www.digitalocean.com/community", "urlHash": "077880af78", "clicks": 0, "createdAt": "2020-01-30T19:15:10.820062+00:00" } } } }
Cùng với đó, một URL đã được thêm vào database với version băm của nó, như bạn thấy trong trường urlHash
. Hãy thử chạy Truy vấn bạn đã tạo ở Bước cuối cùng để xem kết quả của nó:
query { urls { id fullUrl urlHash clicks createdAt } }
Đầu ra sẽ hiển thị URL được lưu trữ:
Output{ "data": { "urls": [ { "id": "1", "fullUrl": "https://www.digitalocean.com/community", "urlHash": "077880af78", "clicks": 0, "createdAt": "2020-03-18T21:03:24.664934+00:00" } ] } }
Bạn cũng có thể thử thực hiện cùng một Truy vấn, nhưng chỉ yêu cầu các trường bạn muốn.
Tiếp theo, hãy thử nó với một URL khác:
mutation { createUrl(fullUrl:"https://www.digitalocean.com/write-for-donations/") { url { id fullUrl urlHash clicks createdAt } } }
Đầu ra sẽ là:
Output{ "data": { "createUrl": { "url": { "id": "2", "fullUrl": "https://www.digitalocean.com/write-for-donations/", "urlHash": "703562669b", "clicks": 0, "createdAt": "2020-01-30T19:31:10.820062+00:00" } } } }
Hệ thống hiện có thể tạo các URL ngắn và liệt kê chúng. Trong bước tiếp theo, bạn sẽ cho phép user truy cập vào một URL bằng version ngắn của nó, chuyển hướng họ đến đúng trang.
Bước 5 - Tạo Điểm cuối Truy cập
Trong bước này, bạn sẽ sử dụng Django Views — một phương thức nhận yêu cầu và trả về phản hồi — để chuyển hướng bất kỳ ai truy cập điểm cuối http://localhost:8000/ url_hash
đến URL đầy đủ của nó.
Mở file shortener/views.py
bằng editor :
- vim shortener/views.py
Để bắt đầu, nhập hai gói bằng cách thay thế nội dung bằng các dòng sau:
from django.shortcuts import get_object_or_404, redirect from .models import URL
Những điều này sẽ được giải thích kỹ hơn ở phần sau.
Tiếp theo, bạn sẽ tạo một Django View có tên root
. Thêm đoạn mã này chịu trách nhiệm về Chế độ xem ở cuối file của bạn:
... def root(request, url_hash): url = get_object_or_404(URL, url_hash=url_hash) url.clicked() return redirect(url.full_url)
Điều này nhận được một đối số được gọi là url_hash
từ URL mà user yêu cầu. Bên trong hàm, dòng đầu tiên cố gắng lấy URL từ database bằng cách sử dụng đối số url_hash
. Nếu không tìm thấy, nó trả về lỗi HTTP 404 cho client , nghĩa là tài nguyên bị thiếu. Sau đó, nó tăng thuộc tính được clicked
của mục nhập URL, đảm bảo theo dõi số lần URL được truy cập. Cuối cùng, nó chuyển hướng khách hàng đến URL được yêu cầu.
Tệp shortener/views.py
đầy đủ được hiển thị ở đây:
from django.shortcuts import get_object_or_404, redirect from .models import URL def root(request, url_hash): url = get_object_or_404(URL, url_hash=url_hash) url.clicked() return redirect(url.full_url)
Lưu và đóng file .
Tiếp theo, mở shorty /urls.py
:
- vim shorty/urls.py
Thêm mã được đánh dấu sau để kích hoạt Chế độ xem root
.
from django.urls import path from django.views.decorators.csrf import csrf_exempt from graphene_django.views import GraphQLView from shortener.views import root urlpatterns = [ path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True))), path('<str:url_hash>/', root, name='root'), ]
Chế độ xem root
sẽ có thể truy cập được trong /
path của server của bạn, chấp nhận url_hash
làm tham số chuỗi.
Lưu và đóng file . Nếu bạn không chạy server local , hãy khởi động nó bằng cách chạy lệnh python manage.py runserver
.
Để kiểm tra phần bổ sung mới của bạn, hãy mở trình duyệt web và truy cập vào URL http://localhost:8000/077880af78
. Lưu ý phần cuối cùng của URL là băm được tạo bởi Mutation từ Bước 5. Bạn sẽ được chuyển hướng đến trang URL của băm, trong trường hợp này là trang web Cộng đồng DigitalOcean.
Đến đây bạn đã chuyển hướng URL hoạt động, bạn sẽ làm cho ứng dụng an toàn hơn bằng cách thực hiện xử lý lỗi khi Mutation được thực thi.
Bước 6 - Thực hiện xử lý lỗi
Xử lý lỗi là cách tốt nhất trong tất cả các ứng dụng, vì các nhà phát triển thường không kiểm soát những gì sẽ được gửi đến server . Trong trường hợp này, bạn có thể cố gắng lường trước những hỏng hóc và giảm thiểu tác động của chúng. Trong một hệ thống phức tạp như GraphQL, rất nhiều thứ có thể xảy ra sai sót, từ client yêu cầu dữ liệu sai đến server mất quyền truy cập vào database .
Là một hệ thống được đánh máy, GraphQL có thể xác minh mọi thứ mà khách hàng yêu cầu và nhận được trong một hoạt động được gọi là Xác thực schemas . Bạn có thể thấy điều này đang hoạt động bằng cách thực hiện một Truy vấn với một trường không tồn tại.
Điều hướng đến http://localhost:8000/graphql
trong trình duyệt của bạn và thực hiện Truy vấn tiếp theo trong giao diện GraphiQL, với trường iDontExist
:
query { urls { id fullUrl urlHash clicks createdAt iDontExist } }
Vì không có trường iDontExist
nào được xác định trong Truy vấn của bạn, GraphQL trả về thông báo lỗi:
Output { "errors": [ { "message": "Cannot query field \"iDontExist\" on type \"URLType\".", "locations": [ { "line": 8, "column": 5 } ] } ] }
Điều này rất quan trọng bởi vì, trong hệ thống đã nhập GraphQL, mục đích là chỉ gửi và nhận thông tin đã được xác định trong schemas .
Ứng dụng hiện tại chấp nhận bất kỳ chuỗi tùy ý nào trong trường full_url
. Vấn đề là nếu ai đó gửi một URL được xây dựng kém, bạn sẽ chuyển hướng user đến hư không khi thử thông tin được lưu trữ. Trong trường hợp này, bạn cần xác minh xem full_url
có được định dạng tốt hay không trước khi lưu nó vào database và nếu có bất kỳ lỗi nào, hãy tăng ngoại lệ GraphQLError
bằng một thông báo tùy chỉnh.
Hãy triển khai chức năng này trong hai bước. Đầu tiên, hãy mở file shortener/models.py
:
- vim shortener/models.py
Thêm các dòng được đánh dấu trong phần nhập:
from hashlib import md5 from django.db import models from django.core.validators import URLValidator from django.core.exceptions import ValidationError from graphql import GraphQLError ...
URLValidator
là một trình trợ giúp Django để xác thực Chuỗi URL và GraphQLError
được Graphene sử dụng để nâng cao các ngoại lệ với một thông báo tùy chỉnh.
Tiếp theo, hãy đảm bảo xác thực URL mà user nhận được trước khi lưu nó vào database . Bật hoạt động này bằng cách thêm mã được đánh dấu trong file shortener/models.py
:
class URL(models.Model): full_url = models.URLField(unique=True) url_hash = models.URLField(unique=True) clicks = models.IntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True) def clicked(self): self.clicks += 1 self.save() def save(self, *args, **kwargs): if not self.id: self.url_hash = md5(self.full_url.encode()).hexdigest()[:10] validate = URLValidator() try: validate(self.full_url) except ValidationError as e: raise GraphQLError('invalid url') return super().save(*args, **kwargs)
Đầu tiên, mã này khởi tạo URLValidator
trong biến validate
. Bên trong khối try/except
, bạn validate()
URL nhận được và đưa ra GraphQLError
với thông báo tùy chỉnh invalid url
nếu có sự cố.
Tệp shortener/models.py
đầy đủ được hiển thị ở đây:
from hashlib import md5 from django.db import models from django.core.validators import URLValidator from django.core.exceptions import ValidationError from graphql import GraphQLError class URL(models.Model): full_url = models.URLField(unique=True) url_hash = models.URLField(unique=True) clicks = models.IntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True) def clicked(self): self.clicks += 1 self.save() def save(self, *args, **kwargs): if not self.id: self.url_hash = md5(self.full_url.encode()).hexdigest()[:10] validate = URLValidator() try: validate(self.full_url) except ValidationError as e: raise GraphQLError('invalid url') return super().save(*args, **kwargs)
Lưu và đóng file . Nếu bạn không chạy server local , hãy khởi động nó bằng lệnh python manage.py runserver
.
Tiếp theo, hãy kiểm tra khả năng xử lý lỗi mới của bạn tại http://localhost:8000/graphql
. Cố gắng tạo một URL mới với full_url
không hợp lệ trong giao diện GraphiQL:
mutation { createUrl(fullUrl:"not_valid_url"){ url { id fullUrl urlHash clicks createdAt } } }
Khi gửi một URL không hợp lệ, ngoại lệ của bạn sẽ được đưa ra với thông báo tùy chỉnh:
Output { "errors": [ { "message": "invalid url", "locations": [ { "line": 2, "column": 3 } ], "path": [ "createUrl" ] } ], "data": { "createUrl": null } }
Nếu bạn nhìn vào terminal của bạn , nơi lệnh python manage.py runserver
đang chạy, lỗi sẽ xuất hiện:
Output ... graphql.error.located_error.GraphQLLocatedError: invalid url [30/Jan/2020 19:46:32] "POST /graphql/ HTTP/1.1" 200 121
Điểm cuối GraphQL sẽ luôn không thành công với mã trạng thái HTTP 200, mã này thường biểu thị thành công. Lưu ý , mặc dù GraphQL được xây dựng dựa trên HTTP, nó không sử dụng các khái niệm về mã trạng thái HTTP hoặc phương thức HTTP như REST.
Với việc xử lý lỗi được triển khai, giờ đây bạn có thể đặt cơ chế lọc các Truy vấn của bạn , giảm thiểu thông tin do server trả về.
Bước 7 - Triển khai bộ lọc
Hãy tưởng tượng bạn đã bắt đầu sử dụng trình rút ngắn URL để thêm các liên kết của riêng mình. Sau một thời gian, sẽ có rất nhiều mục nhập khiến việc tìm kiếm đúng sẽ trở nên khó khăn. Bạn có thể giải quyết vấn đề này bằng cách sử dụng bộ lọc .
Lọc là một khái niệm phổ biến trong các API REST, trong đó Thông số truy vấn thường có một trường và giá trị được thêm vào URL. Ví dụ: để lọc tất cả User có tên jojo , bạn có thể sử dụng GET /api/users?name=jojo
.
Trong GraphQL, bạn sẽ sử dụng Đối số truy vấn làm bộ lọc. Họ tạo ra một giao diện đẹp và sạch sẽ.
Bạn có thể giải quyết vấn đề “khó tìm URL” bằng cách cho phép khách hàng lọc URL theo tên bằng cách sử dụng trường full_url
. Để thực hiện điều đó, hãy mở file shortener/schema.py
trong trình soạn thảo yêu thích của bạn.
- vim shortener/schema.py
Đầu tiên, nhập phương thức Q
trong dòng được đánh dấu:
import graphene from graphene_django import DjangoObjectType from django.db.models import Q from .models import URL ...
Điều này sẽ được sử dụng để lọc truy vấn database của bạn.
Tiếp theo, viết lại toàn bộ lớp Query
với nội dung sau:
... class Query(graphene.ObjectType): urls = graphene.List(URLType, url=graphene.String()) def resolve_urls(self, info, url=None, **kwargs): queryset = URL.objects.all() if url: _filter = Q(full_url__icontains=url) queryset = queryset.filter(_filter) return queryset ...
Các sửa đổi bạn đang thực hiện là:
- Thêm tham số bộ lọc
url
bên trong biếnurls
và phương thức giảiresolve_url
. - Bên trong
resolve_urls
, nếu một tham số có tênurl
được đưa ra, lọc các kết quả database để chỉ trả lại các URL có chứa các giá trị nhất định, sử dụngQ(full_url__icontains=url)
phương pháp.
Tệp shortener/schema.py
đầy đủ được hiển thị ở đây:
import graphene from graphene_django import DjangoObjectType from django.db.models import Q from .models import URL class URLType(DjangoObjectType): class Meta: model = URL class Query(graphene.ObjectType): urls = graphene.List(URLType, url=graphene.String()) def resolve_urls(self, info, url=None, **kwargs): queryset = URL.objects.all() if url: _filter = Q(full_url__icontains=url) queryset = queryset.filter(_filter) return queryset class CreateURL(graphene.Mutation): url = graphene.Field(URLType) class Arguments: full_url = graphene.String() def mutate(self, info, full_url) url = URL(full_url=full_url) url.save() return CreateURL(url=url) class Mutation(graphene.ObjectType): create_url = CreateURL.Field()
Lưu và đóng file . Nếu bạn không chạy server local , hãy khởi động nó bằng python manage.py runserver
.
Kiểm tra các thay đổi mới nhất của bạn tại http://localhost:8000/graphql
. Trong giao diện GraphiQL, hãy viết câu lệnh sau. Nó sẽ lọc tất cả các URL có cộng đồng từ:
query { urls(url:"community") { id fullUrl urlHash clicks createdAt } }
Đầu ra chỉ là một mục nhập vì bạn vừa thêm một URL với chuỗi community
trong đó. Nếu bạn đã thêm nhiều URL trước đó, kết quả của bạn có thể thay đổi.
Output { "data": { "urls": [ { "id": "1", "fullUrl": "https://www.digitalocean.com/community", "urlHash": "077880af78", "clicks": 1, "createdAt": "2020-01-30T19:27:36.243900+00:00" } ] } }
Đến đây bạn có khả năng tìm kiếm thông qua các URL của bạn . Tuy nhiên, với quá nhiều liên kết, khách hàng của bạn có thể phàn nàn rằng danh sách URL đang trả về nhiều dữ liệu hơn những gì ứng dụng của họ có thể xử lý. Để giải quyết điều này, bạn sẽ thực hiện phân trang.
Bước 8 - Thực hiện phân trang
Khách hàng sử dụng chương trình backend của bạn có thể phàn nàn rằng thời gian phản hồi mất quá nhiều thời gian hoặc kích thước của nó quá lớn nếu có quá nhiều mục nhập URL. Ngay cả database của bạn cũng có thể gặp khó khăn khi tập hợp một bộ thông tin khổng lồ. Để giải quyết vấn đề này, bạn có thể cho phép client chỉ định số lượng mục nó muốn trong mỗi yêu cầu bằng cách sử dụng kỹ thuật được gọi là phân trang .
Không có cách mặc định để triển khai tính năng này. Ngay cả trong các API REST, bạn có thể thấy nó trong tiêu đề HTTP hoặc tham số truy vấn, với các tên và hành vi khác nhau.
Trong ứng dụng này, bạn sẽ thực hiện phân trang bằng cách bật thêm hai đối số cho Truy vấn URL: first
và skip
. first
sẽ chọn số phần tử biến đầu tiên và skip
sẽ chỉ định số phần tử nên được bỏ qua ngay từ đầu. Ví dụ: sử dụng first == 10
và skip == 5
sẽ nhận được 10 URL đầu tiên, nhưng bỏ qua 5 trong số đó, chỉ trả lại 5 URL còn lại.
Thực hiện giải pháp này tương tự như thêm một bộ lọc.
Mở file shortener/schema.py
:
- vim shortener/schema.py
Trong file , hãy thay đổi lớp Query
bằng cách thêm hai tham số mới vào biến urls
và phương thức giải resolve_urls
, được đánh dấu trong đoạn mã sau:
import graphene from graphene_django import DjangoObjectType from django.db.models import Q from .models import URL class Query(graphene.ObjectType): urls = graphene.List(URLType, url=graphene.String(), first=graphene.Int(), skip=graphene.Int()) def resolve_urls(self, info, url=None, first=None, skip=None, **kwargs): queryset = URL.objects.all() if url: _filter = Q(full_url__icontains=url) queryset = queryset.filter(_filter) if first: queryset = queryset[:first] if skip: queryset = queryset[skip:] return queryset ...
Mã này sử dụng tham số mới được tạo first
và skip
các tham số bên trong phương thức resolve_urls
để lọc truy vấn database .
Lưu và đóng file . Nếu bạn không chạy server local , hãy khởi động nó bằng python manage.py runserver
.
Để kiểm tra việc phân trang, hãy đưa ra Truy vấn sau trong giao diện GraphiQL tại http://localhost:8000/graphql
:
query { urls(first: 2, skip: 1) { id fullUrl urlHash clicks createdAt } }
Trình rút ngắn URL của bạn sẽ trả về URL thứ hai được tạo trong database của bạn:
Output { "data": { "urls": [ { "id": "2", "fullUrl": "https://www.digitalocean.com/write-for-donations/", "urlHash": "703562669b", "clicks": 0, "createdAt": "2020-01-30T19:31:10.820062+00:00" } ] } }
Điều này cho thấy rằng tính năng phân trang hoạt động. Hãy thoải mái chơi xung quanh bằng cách thêm nhiều URL và thử nghiệm các group khác nhau first
và skip
.
Kết luận
Toàn bộ hệ sinh thái GraphQL đang phát triển mỗi ngày, với một cộng đồng tích cực đằng sau nó. Nó đã được chứng minh là sẵn sàng production bởi các công ty như GitHub và Facebook, và bây giờ bạn có thể áp dụng công nghệ này cho các dự án của riêng mình.
Trong hướng dẫn này, bạn đã tạo dịch vụ rút gọn URL bằng GraphQL, Python và Django, sử dụng các khái niệm như Truy vấn và Đột biến. Nhưng hơn thế nữa, bây giờ bạn đã hiểu cách dựa vào những công nghệ này để xây dựng các ứng dụng web bằng cách sử dụng khuôn khổ web Django.
Bạn có thể khám phá thêm về GraphQL và các công cụ được sử dụng tại đây trong trang web GraphQL và các trang web tài liệu Graphene . Ngoài ra, DigitalOcean có các hướng dẫn bổ sung cho Python và Django mà bạn có thể sử dụng nếu muốn tìm hiểu thêm.
Các tin liên quan