owned this note
owned this note
Published
Linked with GitHub
# Настройка 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()),
]
```