برنامه نویسی

اصل HATEOAS – ایجاد مسیرهای کامل برای اشیا در چارچوب استراحت جنگو.

پیشینه داستان: Pssft – لطفا نزدیکتر شوید.
بنابراین من در این گروه توسعه دهندگان خاص WhatsApp هستم، جایی که موضوعات مختلف مورد بحث قرار می گیرد و اشکال زدایی جفتی از جمله موارد دیگر انجام می شود. ارزشمندترین آنها اطلاعاتی است که به اشتراک گذاشته می شود – از فرصت های شغلی گرفته تا آخرین چارچوب ها و بهترین شیوه ها.
در یک روز نفرین شده، پیوندی به اشتراک گذاشته شد. این یک پیوند به یک پست وبلاگ توسط مایکروسافت بود، عنوان آن “RESTful web API design” بود. تصمیم گرفتم کامل بخوانم و با مفهومی مواجه شدم که “HATEOAS” است (سرد شو! اطلاعات بیشتر در ادامه). می‌توانستم قسم بخورم که قبلاً آن را در جایی دیده‌ام، اما تا کنون واقعاً به آن فکر نکرده‌ام. به سرعت به جلو، آن را گزگز من ؛) بنابراین من تصمیم گرفتم آن را با استفاده از Django Rest Framework (DRF) پیاده سازی کنم و به شما نشان خواهم داد که چگونه.

————— اما در ابتدا چیزی که در مورد HATEOAS یاد گرفتم اینجاست:

اصل HATEOAS چیست؟

HATEOAS (Hypermedia به عنوان موتور حالت برنامه) یک اصل در طراحی API است که هدف آن کشف بیشتر و توصیفی تر API ها است. در ساده ترین عبارت، به این معنی است که یک پاسخ API باید شامل پیوندها یا ارجاع به منابع مرتبط و اقدامات قابل انجام باشد.

تصور کنید در حال مرور یک وب سایت هستید و با یک صفحه محصول روبرو می شوید. در آن صفحه، نه تنها اطلاعات مربوط به محصول را می‌بینید، بلکه پیوندهایی به اقدامات مرتبط مانند «افزودن به سبد خرید»، «مشاهده نظرات» یا «محصولات مشابه» را نیز مشاهده می‌کنید. این پیوندها راهی را در اختیار شما قرار می دهند تا بدون نیاز به ساخت دستی URL یا دانستن کل ساختار وب سایت از قبل، در وب سایت حرکت کنید.

HATEOAS همین مفهوم را برای API ها اعمال می کند. به جای دریافت فقط داده در یک پاسخ API، پاسخ همچنین حاوی پیوندها یا ارجاع به منابع یا اقدامات مرتبط است. این پیوندها می توانند شما را در مورد نحوه تعامل با API و کشف سایر اطلاعات مرتبط راهنمایی کنند. به عنوان مثال، اگر داده‌های مربوط به یک کاربر خاص را دریافت می‌کنید، پاسخ ممکن است شامل پیوندهایی برای به‌روزرسانی نمایه، بازیابی سفارشات یا مشاهده دنبال‌کنندگانش باشد.

با گنجاندن این پیوندها در پاسخ‌های API، مشتریانی که از API استفاده می‌کنند، می‌توانند راحت‌تر با API حرکت کرده و با آن تعامل داشته باشند. آنها نیازی به تکیه بر دانش قبلی یا URL های کدگذاری سخت ندارند، اما می توانند پیوندهای ارائه شده توسط API را برای دسترسی به منابع مختلف یا انجام اقدامات دنبال کنند.

به طور خلاصه، HATEOAS استفاده از API را با گنجاندن پیوندها یا مراجع در پاسخ‌های API ساده می‌کند و به مشتریان اجازه می‌دهد تا به صورت پویاتر با API حرکت کرده و با آن تعامل داشته باشند و قابلیت‌های آن را بدون دانش قبلی گسترده‌تر کشف کنند.

صحبت کافی است، در اینجا پاسخ HATEOAS به نظر می رسد:

نمونه پاسخ HATEOAS Json

در این مثال، ما پاسخی برای یک منبع کتاب داریم. پاسخ شامل شناسه کتاب، عنوان و اطلاعات نویسنده است. نویسنده به عنوان یک شی تودرتو، شامل شناسه و نام آنها نشان داده می شود. علاوه بر این، هم کتاب و هم اشیاء نویسنده دارای یک فیلد “پیوندها” هستند.

فیلد “پیوندها” در شیء کتاب، ارجاعاتی به منابع و اقدامات مرتبط ارائه می دهد. در این مورد:

به طور مشابه، فیلد “پیوندها” در شی نویسنده شامل یک پیوند “خود” است که نشانی اینترنتی منبع نویسنده را فراهم می کند: “https://api.example.com/authors/1”.

این پیوندها به مشتریان اجازه می دهد تا با دنبال کردن URL های ارائه شده، بدون نیاز به ساخت دستی آنها یا داشتن دانش قبلی از ساختار API، در API حرکت کنند. مشتریان می توانند به سادگی با دنبال کردن پیوندهای مناسب در پاسخ API به منابع مرتبط مانند بررسی ها یا یافتن کتاب های مشابه دسترسی پیدا کنند.


پیاده سازی پایه در DRF

پیاده سازی در اینجا نسبتاً سریع و آسان است، اما بسته به مقیاس پروژه ممکن است همیشه اینطور نباشد.

من فرض می‌کنم که شما قبلاً در python، Django و REST دانش دارید، بنابراین من در مورد همه چیزهای ناخوشایند صحبت نمی‌کنم، فقط در صورت نیاز.

اکنون می دانیم که بیشتر درباره HATEOAS چیست – که پیوندهای هایپر رسانه یا منابع را به پاسخ json API خود متصل می کند. با این مقاله من یک روش ساده برای ایجاد چنین پیوند / مسیری را به شما نشان خواهم داد.

الزامات:

– راه اندازی محیط مجازی (برای ویندوز):

$> cd project_folder

$> pip install virtualenv

$> python -m venv venv

$> .\venv\Scripts\activate
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

راه اندازی یک پروژه جنگو:
با اجرای دستور زیر در ترمینال خود یک پروژه جنگو جدید ایجاد کنید:

   pip install django

   pip install djangorestframework

   django-admin startproject library_project
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

یک برنامه جنگو جدید ایجاد کنید:
به دایرکتوری پروژه بروید و یک برنامه جنگو جدید ایجاد کنید، که منطق کتاب ها و نویسندگان را مدیریت می کند:

   cd library_project
   python manage.py startapp library
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مدل ها را تعریف کنید: در library/models.py فایل، مدل هایی را برای کتاب ها و نویسندگان تعریف کنید. مثلا:

   from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return f"/authors/{self.id}/"

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return f"/books/{self.id}/"

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ایجاد سریال ساز: در library/serializers.py فایل، سریال‌ساز برای مدل‌هایی که قبلاً تعریف شده‌اند ایجاد کنید. شامل SerializerMethodField برای ایجاد مسیر کامل برای id رشته.

   from rest_framework import serializers
from library.models import Author, Book

class AuthorSerializer(serializers.ModelSerializer):
    detail = serializers.SerializerMethodField()

    def get_detail(self, obj):
        request = self.context.get('request')
        if request:
            return request.build_absolute_uri(obj.get_absolute_url())
        return obj.id

    class Meta:
        model = Author
        fields = '__all__'

class BookSerializer(serializers.ModelSerializer):
    detail = serializers.SerializerMethodField()
    author = AuthorSerializer()

    def get_detail(self, obj):
        request = self.context.get('request')
        if request:
            return request.build_absolute_uri(obj.get_absolute_url())
        return obj.id

    class Meta:
        model = Book
        fields = '__all__'
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تعریف URL: در library/urls.py فایل، URL ها را برای نقاط انتهایی API تعریف کنید.

   from django.urls import path
from library.views import BookListCreateView, BookRetrieveUpdateDestroyView, AuthorListCreateView

urlpatterns = [
    path('books/', BookListCreateView.as_view(), name='book-list-create'),
    path('books/<int:pk>/', BookRetrieveUpdateDestroyView.as_view(), name='book-retrieve-update-destroy'),
    path('authors/', AuthorListCreateView.as_view(), name='book-list-create'),
]
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ایجاد نماها: در library/views.py فایل، نماهایی برای مدیریت نقاط پایانی API ایجاد کنید.

   from rest_framework import generics
from library.models import Book, Author
from library.serializers import BookSerializer, AuthorSerializer

class BookListCreateView(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class BookRetrieveUpdateDestroyView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class AuthorListCreateView(generics.ListCreateAPIView):
    queryset = Author.objects.all()
    serializer_class = AuthorSerializer
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برنامه را در تنظیمات پروژه قرار دهید: در library_project/settings.py فایل، شامل library برنامه و پیکربندی چارچوب REST.

   INSTALLED_APPS = [
       # Other apps...
       'library',
       'rest_framework',
   ]

   REST_FRAMEWORK = {
       'DEFAULT_RENDERER_CLASSES': [
           'rest_framework.renderers.JSONRenderer',
       ]
   }
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیوندی به آدرس‌های اینترنتی برنامه در فایل urlr.py پروژه اضافه کنید: در library_project/urls.py فایل، شامل:

from django.contrib import admin
from django.urls import path, include # import include

urlpatterns = [
    path('admin/', admin.site.urls),
    # include the library app urls module
    path('', include('library.urls')),
]
   }
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Run migrations: مهاجرت های پایگاه داده را برای ایجاد جداول لازم برای مدل ها اعمال کنید:

   python manage.py makemigrations
   python manage.py migrate
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سرور توسعه را راه اندازی کنید: سرور توسعه را برای آزمایش API راه اندازی کنید:

   python manage.py runserver
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

درخواست و پاسخ به این صورت است:

درخواست:

curl --location 'http://127.0.0.1:8000/books/'
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

واکنش:

[
    {
        "id": 1,
        "detail": "http://127.0.0.1:8000/books/1/",
        "author": {
            "id": 1,
            "detail": "http://127.0.0.1:8000/authors/1/",
            "name": "Stephen Nwankwo"
        },
        "title": "Tales of Ogun"
    },
    {
        "id": 2,
        "detail": "http://127.0.0.1:8000/books/2/",
        "author": {
            "id": 1,
            "detail": "http://127.0.0.1:8000/authors/1/",
            "name": "Stephen Nwankwo"
        },
        "title": "Tales of Ogun"
    }
]
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


آیا ما واقعاً به HATEOAS نیاز داریم؟

چرا ممکن است نیاز به پیاده سازی HATEOAS داشته باشید

من تعدادی از APIها را مرور کردم و در واقع با اجرای HATEOS مواجه نشدم. بنابراین در مورد اینکه آیا کسی به آن نیاز دارد یا نه واقعاً به شما بستگی دارد که توسعه دهنده یا مدیر پروژه هستید.

برای کمک به شما در تصمیم گیری، بسته به الزامات و اهداف خاص پروژه شما. در اینجا چند نکته قابل تامل است:

  1. قابلیت کشف پیشرفته: HATEOAS ماهیت توصیفی خود را برای APIها فراهم می کند و به مشتریان اجازه می دهد منابع موجود را به صورت پویا کشف و پیمایش کنند. این نیاز مشتریان را به تکیه بر دانش قبلی یا URL های رمزگذاری شده حذف می کند و باعث می شود API بصری تر و استفاده آسان تر باشد.

  2. کوپلینگ کاهش یافته: با گنجاندن پیوندها یا ارجاع به منابع مرتبط در پاسخ های API، HATEOAS جفت شدن بین کلاینت ها و سرورها را کاهش می دهد. مشتریان می توانند پیوندهای ارائه شده را برای دسترسی به منابع مختلف دنبال کنند و بدون نیاز به دانستن کل ساختار API از قبل، اقداماتی را انجام دهند. این امر اتصال شل را تقویت می کند و سیستم های انعطاف پذیرتر و قابل گسترش تر را قادر می سازد.

  3. مقیاس‌پذیری بهبود یافته: HATEOAS سرور را قادر می‌سازد تا تکامل یابد و منابع یا اقدامات جدید را بدون شکستن کلاینت‌های موجود اضافه کند. مشتریانی که پیوندهای ارائه شده در پاسخ‌های API را دنبال می‌کنند، می‌توانند بدون نیاز به تغییر در کد خود، با تغییرات در API سازگار شوند. این باعث می‌شود که API مقیاس‌پذیرتر شود و نسخه‌سازی و سازگاری به عقب را تسهیل کند.

  4. سادگی توسعه مشتری: HATEOAS توسعه مشتری را با ارائه یک رویکرد هدایت شده برای تعامل API ساده می کند. مشتریان می توانند به جای ساختن URL ها به صورت دستی یا کدگذاری سخت، به پیوندهای ارائه شده در پاسخ های API تکیه کنند. این باعث کاهش پیچیدگی و خطاهای احتمالی در کد مشتری می شود.

  5. سازگاری و مستندسازی: HATEOAS یکپارچگی را ترویج می‌کند و شکلی از خود مستندسازی را در خود API ارائه می‌کند. پیوندهای موجود در پاسخ‌ها به عنوان مرجعی به اقدامات و منابع موجود عمل می‌کنند و درک و استفاده مؤثر از API را برای توسعه‌دهندگان آسان‌تر می‌کنند.

با این حال، توجه به این نکته مهم است که اجرای HATEOAS به فرآیند طراحی و توسعه API پیچیدگی می‌افزاید. این امر مستلزم بررسی دقیق پیوندهایی است که باید در آن گنجانده شوند، ایجاد تعادل بین ارائه اطلاعات کافی و جلوگیری از غلبه بر مشتریان با پیوندهای بیش از حد. علاوه بر این، HATEOAS ممکن است برای همه موارد استفاده از API ضروری یا مناسب نباشد، به خصوص زمانی که دامنه API کوچک است یا تعامل مشتری و سرور ساده است.

در نهایت، تصمیم به استفاده از HATEOAS باید بر اساس عواملی مانند پیچیدگی API شما، سطح مورد نظر از قابلیت کشف و انعطاف پذیری و نیازهای مشتریان شما باشد.


لطفا اگر مقاله را مفید دیدید لایک کنید و نظرات خود را در قسمت نظرات به اشتراک بگذارید.

منابع:

https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design

https://www.geeksforgeeks.org/hateoas-and-why-its-needed-in-restful-api/

https://www.w3schools.in/restful-web-services/rest-apis-hateoas-concept#google_vignette

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا