# Настройка API --- ## Что такое API ---- Аббревиатура API расшифровывается как «Application Programming Interface» (интерфейс программирования приложений, программный интерфейс приложения). ---- Чтобы понять, как и каким образом API применяется в разработке и бизнесе, сначала нужно разобраться, как устроена «всемирная паутина». ---- WWW можно представить как огромную сеть связанных серверов, на которых и хранится каждая страница. ---- При введении в адресную строку браузера `www.facebook.com` на удалённый сервер Facebook отправляется соответствующий запрос. Как только браузер получает ответ, то интерпретирует код и отображает страницу. ---- Каждый раз, когда пользователь посещает какую-либо страницу в сети, он взаимодействует с API удалённого сервера. API — это составляющая часть сервера, которая получает запросы и отправляет ответы. ---- Чем API отличается от привычных нам методов? Разница в формате запроса и ответа. Чтобы сгенерировать полную веб-страницу, браузер ожидает ответ на языке разметки HTML, в то время как API Google Календаря вернёт просто данные в формате вроде JSON. ---- Пользователь благодаря API получает возможность совершить действие, не покидая сайт компании. ---- Многие разработчики разносят приложение на несколько серверов, которые взаимодействуют между собой при помощи API. Серверы, которые выполняют вспомогательную функцию по отношению к главному серверу приложения, называются микросервисами. ---- Слово «application» (прикладной, приложение) может применяться в разных значениях. В контексте API оно подразумевает: * фрагмент программного обеспечения с определённой функцией, * сервер целиком, приложение целиком или же просто отдельную часть приложения. --- ## Вызов API напрямую ---- ### Система вызывает функции внутри себя Разные части программы как-то общаются между собой. Они делают это на программном уровне, то есть на уровне API! Это самый «простой» в использовании способ, потому что автор API, которое вызывается — разработчик. ---- ### Система вызывает метод другой системы Одна система дергает через api какой-то метод другой системы. Она может попытаться получить данные из другой системы. Или наоборот, отправить данные в эту систему. ---- ### Человек вызывает метод Причины разные: * Для ускорения работы * Для локализации бага (проблема где? На сервере или клиенте?) * Для проверки логики без докруток фронта Если система предоставляет API, обычно проще дернуть его, чем делать то же самое через графический интерфейс. Тем более что вызов API можно сохранить в инструменте. Один раз сохранил — на любой базе применяешь, пусть даже она по 10 раз в день чистится. ---- ### Косвенный вызов API Когда пользователь работает с GUI, на самом деле он тоже работает с API. Просто не знает об этом, ему это просто не нужно. То есть когда пользователь открывает систему и пытается загрузить отчет, ему не важно, как работает система, какой там magic внутри. У него есть кнопочка «загрузить отчет», на которую он и нажимает. Пользователь работает через GUI (графический пользовательский интерфейс). --- ## Как работает Django REST framework ---- Django Rest Framework (DRF) — это библиотека, которая работает со стандартными моделями Django для создания гибкого и мощного API для проекта. ---- API DRF состоит из 3-х слоев: сериализатора, вида и маршрутизатора. * Сериализатор * Вид (ViewSet) * Маршрутизатор ---- Модели Django интуитивно представляют данные, хранящиеся в базе, но API должен передавать информацию в менее сложной структуре. Хотя данные будут представлены как экземпляры классов Model, их необходимо перевести в формат JSON для передачи через API. ---- Сериализатор DRF производит это преобразование. Когда пользователь передает информацию (например, создание нового экземпляра) через API, сериализатор берет данные, проверяет их и преобразует в нечто, что Django может сложить в экземпляр модели. ---- Наиболее распространенной формой, которую принимает сериализатор DRF, является тот, который привязан непосредственно к модели Django: ``` class ThingSerializer(serializers.ModelSerializer): class Meta: model = Thing fields = ('name', ) ``` ---- Сериализатор анализирует информацию в обоих направлениях (чтение и запись), тогда как ViewSet - это тот код, в котором определены доступные операции. ---- Наиболее распространенным ViewSet является ModelViewSet, который имеет следующие встроенные операции: Создание экземпляра: create() Получение / чтение экземпляра: retrieve() Обновление экземпляра (все или только выбранные поля): update() или partial_update() Уничтожение / Удаление экземпляра: destroy() Список экземпляров (с разбивкой по страницам по умолчанию): list() ---- Каждая из этих функций может быть переопределена, если требуется другое поведение, но стандартная функциональность работает с минимальным кодом, а именно: ``` class ThingViewSet(viewsets.ModelViewSet): queryset = Thing.objects.all() ``` ---- И наконец, маршрутизаторы: они предоставляют верхний уровень API. ---- тобы избежать создания бесконечных URL-адресов вида: «списки», «детали» и «изменить», маршрутизаторы DRF объединяют все URL-адреса, необходимые для данного вида в одну строку для каждого ViewSet, например: ``` # Инициализация роутера DRF. Только один раз на файл urls.py # из маршрутизаторов импорта rest_framework router = routers.DefaultRouter() # Регистрация ViewSet router.register(r'thing', main_api.ThingViewSet) ``` ---- Затем все ViewSet, которые зарегистрированны в маршрутизаторе, можно добавить к обычным url_patterns: `<kbd>url_patterns + = url (r '^', include (router.urls))</kbd>` Теперь через API можно получить данные точно так же, как и любые другие обычные страницы Django. --- ## Настройка API в приложении ---- Установим библиотеки Django REST framework и django-cors-headers, для чего наберем команды: ``` pip install djangorestframework pip install django-cors-headers ``` ---- Сразу же создадим новое приложение api, в котором и реализуем функциональность веб-службы: `python manage.py startapp api` ---- Добавим приложения rest_framework И corsheaders — Программные Ядра ТОЛЬКО что установленных библиотек, а также только что созданное приложение api в список зарегистрированных в проекте: ``` INSTALLED_APPS = [ ... 'rest_framework', 'corsheaders', 'api.apps.ApiConfig', ] ``` ---- Добавим в список зарегистрированных в проекте необходимый для работы посредник: ``` MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', ] ``` ---- He забудем указать там же, в модуле settings.py пакета конфигурации, настройки, разрешающие доступ к веб-службе с любого домена: ``` CORS_ORIGIN_ALLOW_ALL = True CORS_URLS_REGEX = r'^/api/.*$' ``` ---- Создадим в пакете приложения api модуль serializers.py. В нем сохраним код сериализатора BbSerializer, формирующего список объявлений. ``` from rest_framework import serializers from main.models import Bb class BbSerializer(serializers.ModelSerializer): class Meta: model = Bb fields = ('id', 'title', 'content', 'price', 'created_at') ``` ---- онтроллер, который будет выдавать список объявлений, реализуем в виде функции и назовем bbs(). ``` from rest_framework.response import Response from rest_framework.decorators import api_view from main.models import Bb from .serializers import BbSerializer @api_view(['GET']) def bbs(request): if request.method == 'GET': bbs = Bb.objects.filter(is_active=True)[:10] serializer = BbSerializer(bbs, many=True) return Response(serializer.data) ``` ---- Откроем список маршрутов уровня проекта (модуль urls.py пакета конфигурации) и добавим маршрут, указывающий на приложение api: ``` urlpatterns = [ ... path('api/', include('api.urls')), path('', include('main.urls')), ] ``` ---- В пакете приложения api создадим модель urls.py, в который запишем список маршрутов уровня этого приложения. ``` from django.urls import path from .views import bbs urlpatterns = [ path('bbs/', bbs), ] ``` ---- Сохраним код, запустим отладочный веб-сервер и попробуем получить список объявлений, перейдя по интернет-адресу `http://localhost:8000/api/bbs/`. Если мы все сделали правильно, то увидим веб-представление, показывающее последние 10 объявлений, которые были оставлены посетителями сайта. ---- Занесем код сериализатора BbDetaiiserializer, выдающего сведения об объявлении в модуль serializers.py пакета приложения. ``` class BbDetailSerializer(serializers.ModelSerializer): class Meta: model = Bb fields = ('id', 'title', 'content', 'price', 'created_at', 'contacts', 'image') ``` ---- Контроллер назовем BbDetailView и реализуем в виде класса, производного от класса RetrieveAPIView. Его код, весьма компактный. ``` from rest_framework.generics import RetrieveAPIView from .serializers import BbDetailSerializer class BbDetailView(RetrieveAPIView): queryset = Bb.objects.filter(is_active=True) serializer_class = BbDetailSerializer ``` ---- Добавим в список маршрутов уровня приложения маршрут, который укажет на наш новый контроллер: ``` from .views import BbDetailView urlpatterns = [ path('bbs/<int:pk>/', BbDetailView.as_view()), path('bbs/', bbs), ] ``` ---- Код сериализатора Commentserializer, который будет отправлять список комментариев и добавлять новый комментарий. ``` from main.models import Comment class CommentSerializer(serializers.ModelSerializer): class Meta: model = Comment fields = ('bb', 'author', 'content', 'created_at') ``` ---- од контроллера-функции comments(), выдающего список комментариев и добавляющего новый комментарий. ``` from rest_framework.decorators import permission_classes from rest_framework.status import HTTP_201_CREATED, HTTP_400_BAD_REQUEST from rest_framework.permissions import IsAuthenticatedOrReadOnly from main.models import Comment from .serializers import CommentSerializer @api_view(['GET', 'POST']) @permission_classes((IsAuthenticatedOrReadOnly,)) def comments(request, pk): if request.method == 'POST': serializer = CommentSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=HTTP_201_CREATED) else: return Response(serializer.errors, status=HTTP_400_BAD_REQUEST) else: comments = Comment.objects.filter(is_active=True, bb=pk) serializer = CommentSerializer(comments, many=True) return Response(serializer.data) ``` ---- Маршрут, который укажет на новый контроллер и который мы поместим в список уровня приложения, будет выглядеть так: ``` from .views import comments urlpatterns = [ path('bbs/<int:pk>/comments/' , comments), path('bbs/<int:pk>/', BbDetailView.as_view()), ] ```
{"metaMigratedAt":"2023-06-16T18:25:24.923Z","metaMigratedFrom":"Content","title":"Настройка API","breaks":true,"contributors":"[{\"id\":\"0d39d5a3-691d-488c-8f1e-1a0fb0be4f13\",\"add\":10723,\"del\":1}]"}
    268 views