• 01 Апр
  • 2015
API на Django со сложной структурой и прочими плюшками
Это статья из серии "Simple API". Вы также можете почитать другие статьи из этой серии:
  1. API на Django со сложной структурой и прочими плюшками
  2. Списки возможных значений и типы данных SimpleAPI

Так вышло, что уже не первый раз приходится писать некий сервис для корпоративного использования. По причине его приватности не буду рассказывать о функционале, скажу лишь, что бизнес крепко связан с вебом. Отличным продолжением работы сервиса оказалось написание аддонов для Firefox, которые существенно упрощают жизнь персоналу. Для этого пришлось написать API, чтобы можно было получать информацию с сервера, а также записывать ее. Для этого я создал простое представление, которое наполнил необходимыми условиями и функциями. Все бы было хорошо, если бы и без того широкий ассортимент возможностей не расширялся со скоростью звука, а уже существующий не требовал внесения изменений. Постепенно код этого представления приобрел завидные размеры, а счет строкам пошел уже на сотни. Когда же я решил добавить какую-нибудь простенькую валидацию данных, чтобы защититься от "неправильных" параметров, предстваление стало похоже на рукописи средневековых монахов, а прочитать его можно было только совершив обряд изнания демонов. В конце концов мое терпение лопнуло и я решил написать модуль для Django, который бы существенно упростил написание подобных API, а путь их модификации стал мягким и шелковистым.

Встречайте, SimpleAPI

Так просто и незамысловато я назвал свой модуль, какбы намекая на его простоту :)

Установка и подключение модуля простые:

1. pip install simple_api

2. Подключаем модуль в settings.py

INSTALLED_APPS = (
    ...
    'simple_api',
)

3. Коннектим модуль и прописываем urlpatterns в urls.py

import simple_api
simple_api.connect()


url(r'api/', include(simple_api.urls)),

4. Создаем файл api_models.py в приложении, к которому нужно подключить API. Нужно отметить, что модуль будет искать все файлы с таким именем, которые лежат в корне приложений Django, и создавать на их основе необходимый функционал, доступный через API.

Что позволяет делать SimpleAPI?

При его написании я руководствовался принципами моделей Django, поэтому старался сделать что-то подобное. Функции API - обычные классы, которые, как и модели, наследуются от другого класса. Переменные класса - это возможные параметры, которые может принимать функция. Приведем простой пример функции, которая будет возвращать произведение двух целых чисел.

# api_models.py
import simple_api


class Multiplication(simple_api.SimpleAPI):
    a = simple_api.IntegerVariable()
    b = simple_api.IntegerVariable()

    def method(self):
        return int(self.a.get()) * int(self.b.get())

 

Теперь если вы перейдете по ссылке http://127.0.0.1:8000/api/multiplication/?a=5&b=3, то получите ответ:

{"status": "ok", "runtime": 0.0, "data": 15}

Здесь мы видим, что функция выполнилась без ошибок (status), время выполнения заняло менее одной тысячной доли секунды (runtime), результат выполнения скрипта = 15 (data).

Это простой пример, на котором сложно оценить полезность модуля, так как функцию умножения двух чисел можно было бы написать с меньшими заботами. Но за кулисами произошло еще несколько важных моментов, которые мы сразу не заметили: валидация и формирование мануала.

Если мы перейдем по той же ссылке, но не указав параметры a и b, то получим такой результат:

{"status": "error", "data": "Expected parameter 'a'"}

Статус "ошибка" и сообщение, что мы не указали обязательный параметр 'a'.

Если мы укажем в качестве значений параметров a и b не числа, а строки http://127.0.0.1:8000/test_api/multiplication/?a=a&b=b, то получим ответ:

{"status": "error", "data": "Wrong data type of 'a'"}

Снова ошибка, и сообщение о неправильном формате параметра 'a'.

Если же мы ошибемся в названии функции и пройдем, например, по такой ссылке: http://127.0.0.1:8000/test_api/pultiplication/ , то получаем ошибку, что функция pultiplication неизвестна:

{"status": "error", "data": "Unknown method pultiplication"}

Теперь давайте перейдем по адресу http://127.0.0.1:8000/test_api/manual/ и получим краткую инструкцию о нашей мегафункции:

SimpleAPI manual


Multiplication - Simple API method:
	<integer>	a		[mondatory]	(default: None)  	- API variable.
	<integer>	b		[mondatory]	(default: None)  	- API variable.

 Я уже говорил, что старался максимально приблизить SimpleAPI к джанговским моделям, соответственно не смог обойти такие важные параметры как blank и default. Давайте немного изменим нашу функцию и сделаем ее параметры необязательными. Но для того, чтобы функция не завершилась с ошибкой, зададим значения по умолчанию.

class Multiplication(simple_api.SimpleAPI):
    a = simple_api.IntegerVariable(blank=True, default=10)
    b = simple_api.IntegerVariable(blank=True, default=5)

Теперь мы можем вызывать метод Multiplication без параметров и получать ответ без ошибок.

comments powered by Disqus