Если вы читаете эту статью, вы, вероятно, знакомы с возможностями, которые открываются при использовании API (интерфейс прикладного программирования).

Используя один из множества общедоступных API-интерфейсов, вы можете расширить функциональность своего приложения или обогатить его необходимыми данными.

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

Ответ - создать свой собственный API.

По теме: Как использовать API с Python

Хотя на первый взгляд это может показаться сложной задачей, на самом деле это довольно просто.

Ниже мы расскажем, как это сделать с помощью Python.

Требования

Для создания API мы будем использовать:

Нам также понадобится Flask-RESTful, расширение для Flask, которое позволяет быстро разрабатывать REST API с минимальной настройкой. Установка осуществляется командой:

pip install flask-restful

Прежде, чем мы начнем

Мы собираемся разработать RESTful API, который реализует базовую функциональность CRUD.

Чтобы полностью понять проблему, давайте углубимся в эти два термина, упомянутых выше:

Что такое ОТДЫХ?

REST API (передача репрезентативного состояния) - это API, использующий HTTP-запросы для связи.

API REST должны соответствовать определенным ограничениям. Вот несколько:

  • Клиентская -серверная архитектура - клиент управляет пользовательским интерфейсом, а сервер управляет бэкэндом и хранением данных. Клиент и сервер независимы, и каждый из них может быть заменен отдельно.
  • Без сохранения состояния - данные от клиента не хранятся на стороне сервера. Состояние сеанса хранится на стороне клиента.
  • Cacheable - клиенты могут кэшировать ответы сервера для повышения производительности.

Что такое CRUD?

CRUD - это концепция программирования, которая определяет четыре основных действия (c reate, r ead, u pdate и d elete), который может выполняться с данными.

В REST API за эти действия отвечают типы запросов или методы запросов:

  • POST: создать действие. Добавляет новые данные на сервер. Используя этот тип запроса, мы можем, например, добавить новую запись в блог.
  • GET: прочитать действие. Получить информацию. Это самый распространенный тип запроса. С его помощью мы можем, например, получить список сообщений в блоге.
  • PUT: действие обновления. Изменяет существующую информацию. Например, с помощью этого типа запроса можно будет изменить текст существующей статьи.
  • УДАЛИТЬ: действие удаления. Удаляет существующую информацию, например сообщение в блоге, которая нам больше не интересна.

Теперь, когда мы понимаем основные термины, мы можем приступить к созданию нашего API.

Реализация

Создадим хранилище цитат об искусственном интеллекте (ИИ).

Сегодня ИИ - одна из самых быстрорастущих отраслей человеческой деятельности, а Python - популярный инструмент для работы с ИИ.

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

Если у разработчика есть свои стоящие мысли на эту тему, то он сможет добавить их в репозиторий.

Начнем с импорта необходимых модулей и настройки приложения Flask:

from flask import Flask
from flask_restful import Api, Resource, reqparse
import random
app = Flask(__name__)
api = Api(app)

В указанном фрагменте кода Flask, Api и Resource - это классы, с которыми нам нужно будет работать.

Reqparse - это интерфейс синтаксического анализа запросов Flask-RESTful. Также нам понадобится random модуль для отображения случайной цитаты.

Далее мы создадим репозиторий цитат об ИИ.

Каждая запись в репозитории будет содержать:

  • числовой идентификатор,
  • имя автора цитаты,
  • и сама цитата.

Поскольку это обучающий пример, мы будем хранить все записи в списке Python. В реальном приложении мы, вероятно, использовали бы вместо этого базу данных.

ai_quotes = [
    {
        "id": 0,
        "author": "Kevin Kelly",
        "quote": "The business plans of the next 10,000 startups are easy to forecast: " +
                 "Take X and add AI." 
    },
    {
        "id": 1,
        "author": "Stephen Hawking",
        "quote": "The development of full artificial intelligence could " +
                 "spell the end of the human race…. " +
                 "It would take off on its own, and re-design " +
                 "itself at an ever increasing rate. " +
                 "Humans, who are limited by slow biological evolution, " + 
                 "couldn't compete, and would be superseded."
    },
    {
        "id": 2,
        "author": "Claude Shannon",
        "quote": "I visualize a time when we will be to robots what " +
                 "dogs are to humans, " + 
                 "and I’m rooting for the machines."
    },
    {
        "id": 3,
        "author": "Elon Musk",
        "quote": "The pace of progress in artificial intelligence " +
                 "(I’m not referring to narrow AI) " +
                 "is incredibly fast. Unless you have direct " +
                 "exposure to groups like Deepmind, " +
                 "you have no idea how fast—it is growing " + 
                 "at a pace close to exponential. " +
                 "The risk of something seriously dangerous " +
                 "happening is in the five-year timeframe." + 
                 "10 years at most."
    },
    {
        "id": 4,
        "author": "Geoffrey Hinton",
        "quote": "I have always been convinced that the only way " +
                 "to get artificial intelligence to work " + 
                 "is to do the computation in a way similar to the human brain. " +
                 "That is the goal I have been pursuing. We are making progress, " +
                 "though we still have lots to learn about " +
                 "how the brain actually works."
    },
    {
        "id": 5,
        "author": "Pedro Domingos",
        "quote": "People worry that computers will " +
                 "get too smart and take over the world, " + 
                 "but the real problem is that they're too stupid " +
                 "and they've already taken over the world."
    },
    {
        "id": 6,
        "author": "Alan Turing",
        "quote": "It seems probable that once the machine thinking " +
                 "method had started, it would not take long " +
                 "to outstrip our feeble powers… " +
                 "They would be able to converse " +
                 "with each other to sharpen their wits. " +
                 "At some stage therefore, we should " +
                 "have to expect the machines to take control."
    },
    {
        "id": 7,
        "author": "Ray Kurzweil",
        "quote": "Artificial intelligence will reach " +
                 "human levels by around 2029. " + 
                 "Follow that out further to, say, 2045, " +
                 "we will have multiplied the intelligence, " + 
                 "the human biological machine intelligence " +
                 "of our civilization a billion-fold."
    },
    {
        "id": 8,
        "author": "Sebastian Thrun",
        "quote": "Nobody phrases it this way, but I think " +
                 "that artificial intelligence " +
                 "is almost a humanities discipline. It's really an attempt " +
                 "to understand human intelligence and human cognition."
    },
    {
        "id": 9,
        "author": "Andrew Ng",
        "quote": "We're making this analogy that AI is the new electricity." + 
                 "Electricity transformed industries: agriculture, " +
                 "transportation, communication, manufacturing."
    }
]

Теперь давайте создадим Quote класс ресурсов.

Он будет определять работу конечных точек нашего API. Внутри класса мы определим четыре метода (помните: получить, опубликовать, поместить, удалить).

Начнем с метода GET.

С помощью этого метода мы можем получить конкретную цитату, указав ее id, или получить случайную цитату, если id не указан:

class Quote(Resource):
    def get(self, id=0):
        if id == 0:
            return random.choice(ai_quotes), 200
        for quote in ai_quotes:
            if(quote["id"] == id):
                return quote, 200
        return "Quote not found", 404

Метод GET возвращает случайную цитату, если id содержит значение по умолчанию (то есть id не был указан при вызове метода).

Если указан id, метод перебирает все записи в репозитории кавычек и возвращает результат, соответствующий указанному id.

Если запись не может быть найдена, метод возвращает соответствующее сообщение («Цитата не найдена, 404»).

Обратите внимание, что метод возвращает Код состояния HTTP 200 для каждого ответа, если запрос выполнен успешно, и 404, если запись не найдена.

Затем давайте создадим метод POST, чтобы добавить новую цитату в репозиторий.

Этот метод получит на вход идентификатор новой котировки. Кроме того, POST будет использовать reqparse для анализа параметров, которые войдут в тело запроса (автор и текст цитаты).

def post(self, id):
      parser = reqparse.RequestParser()
      parser.add_argument("author")
      parser.add_argument("quote")
      params = parser.parse_args()
      for quote in ai_quotes:
          if(id == quote["id"]):
              return f"Quote with id {id} already exists", 400
      quote = {
          "id": int(id),
          "author": params["author"],
          "quote": params["quote"]
      }
      ai_quotes.append(quote)
      return quote, 201

В приведенном выше фрагменте кода метод POST принимает id цитаты. Затем, используя reqparse, он получает автора и цитату из запроса и сохраняет их в словаре параметров.

Если цитата с указанным идентификатором уже существует, метод возвращает соответствующее сообщение и код состояния 400.

Если цитата с указанным идентификатором еще не создана, метод создает новую запись с указанным идентификатором и параметрами автора и цитаты. Затем он добавляет запись в список ai_quotes, а затем возвращает запись с новой цитатой и кодом состояния 201.

Теперь мы создадим метод PUT для изменения содержимого существующей цитаты в репозитории:

def put(self, id):
      parser = reqparse.RequestParser()
      parser.add_argument("author")
      parser.add_argument("quote")
      params = parser.parse_args()
      for quote in ai_quotes:
          if(id == quote["id"]):
              quote["author"] = params["author"]
              quote["quote"] = params["quote"]
              return quote, 200
      
      quote = {
          "id": id,
          "author": params["author"],
          "quote": params["quote"]
      }
      
      ai_quotes.append(quote)
      return quote, 201

Точно так же в предыдущем примере метод PUT принимает на входе id, а затем анализирует параметры котировки с помощью reqparse.

Если цитата с указанным идентификатором существует, метод обновит ее проанализированными параметрами и вернет обновленную цитату с кодом состояния 200.

Если еще нет котировки с указанным идентификатором, будет создана новая запись, которая будет возвращена с кодом состояния 201.

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

def delete(self, id):
      global ai_quotes
      ai_quotes = [qoute for qoute in ai_quotes if qoute["id"] != id]
      return f"Quote with id {id} is deleted.", 200

Метод DELETE получает идентификатор котировки на входе и обновляет список ai_quotes через глобальную область видимости, используя понимание списка.

Теперь, когда мы создали все методы в нашем ресурсе Quote, все, что нам нужно сделать, это добавить ресурс в наш API, указать его маршруты и запустить наше приложение Flask:

api.add_resource(Quote, "/ai-quotes", "/ai-quotes/", "/ai-quotes/<int:id>")
if __name__ == '__main__':
    app.run(debug=True)

Наша служба REST API готова!

Теперь мы можем сохранить наш код в файле app.py и запустить его в консоли с помощью команды:

python3 app.py

Если все в порядке, то мы должны увидеть что-то вроде следующих строк:

* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: XXXXXXX

Тестирование API

Теперь, когда мы создали наш API, давайте протестируем его!

Мы можем протестировать наш API-сервис с помощью консольной утилиты curl или REST-клиента Insomnia или опубликовав его на RapidAPI.

Публикация вашего API

RapidAPI - крупнейшая в мире торговая площадка с более чем 10 000 API (и более 1 000 000 разработчиков).

RapidAPI не только предоставляет единый интерфейс для работы со сторонними API, но также дает возможность быстро и без проблем публиковать собственный API.

Чтобы опубликовать наш API на RapidAPI, нам нужно сначала опубликовать его на каком-нибудь сервере в Интернете.

В нашем случае воспользуемся Heroku. Опубликовать API на Heroku довольно просто (подробнее здесь).

Как опубликовать свой API на Heroku

1. Установите Heroku

Во-первых, нам нужно зарегистрировать учетную запись Heroku и установить интерфейс командной строки (CLI) Heroku с помощью следующей команды (работает с Ubuntu 16+):

sudo snap install heroku --classic

Затем войдите в интерфейс командной строки Heroku:

heroku login

2. Добавьте необходимые файлы.

Теперь давайте добавим необходимые файлы для публикации в папку в нашем приложении:

  • requirements.txt со списком необходимых модулей Python.
  • Procfile, в котором явно указывается, какие команды должны быть выполнены для запуска нашего приложения.
  • .gitignore, чтобы исключить файлы, которые нам не нужны на сервере.

Наш файл requirements.txt будет содержать следующие строки:

flask
flask-restful
gunicorn

Обратите внимание, что мы добавили gunicorn (Python WSGI HTTP Server) в наш список, поскольку это необходимо для запуска нашего приложения на сервере.

Procfile будет содержать:

web: gunicorn app:app

и .gitignore будут содержать следующее:

*.pyc
__pycache__/

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

git init
git add .
git commit -m "First API commit"

3. Создайте новое приложение Heroku.

heroku create

И, наконец, отправьте нашу основную ветку в удаленный репозиторий Heroku:

git push heroku master

Теперь мы можем запустить и открыть нашу службу API с помощью команд:

heroku ps:scale web=1
heroku open

Теперь наш API будет доступен по адресу: https://your-random-heroku-name.herokuapp.com/ai-quotes/

Как добавить свой Python API на рынок RapidAPI

Теперь, когда наш API-сервис опубликован на Heroku, мы можем добавить его в RapidAPI. Вы можете найти подробную документацию здесь для начала работы:

1. Создайте учетную запись RapidAPI.

Сначала зарегистрируйте бесплатную учетную запись RapidAPI. Вы можете сделать это через Facebook, Google или даже через свою учетную запись Github.

2. Добавьте свой API через панель управления провайдера.

Перейдите на https://provider.rapidapi.com и нажмите Добавить новый API.

Отсюда вам нужно будет ввести общую информацию о вашем API.

После нажатия «Добавить API» откроется страница определения обзора API. Здесь мы можем добавить дополнительную информацию о нашем API.

Теперь мы можем либо вручную ввести конечные точки вашего API, либо загрузить файл swagger с помощью OpenAPI.

Давайте определим конечные точки нашего API на странице конечных точек. В нашем случае конечные точки соответствуют концепции CRUD (получение, публикация, размещение, удаление).

Создайте конечную точку GET AI Quote, которая будет возвращать случайную цитату (если параметр id имеет значение по умолчанию) или цитату, соответствующую определенному идентификатору.

Чтобы создать конечную точку, нажмите кнопку «Создать конечную точку».

Повторите этот процесс для всех других конечных точек API.

Вот и все! Поздравляем, вы опубликовали свой API!

Если все пойдет хорошо, у вас будет страница API, которая выглядит так:

Заключение

В этой статье мы изучили процесс создания нашей собственной службы RESTful API на Python, процесс публикации API на облачной платформе Heroku и последующего добавления его в каталог RapidAPI.

Хотя мы изучали основные принципы разработки API, мы не углублялись в вопросы безопасности, отказоустойчивости и масштабируемости API.

В реальных (производственных) условиях эти вопросы обязательно нужно учитывать.

Связанные ресурсы

Первоначально опубликовано на https://blog.rapidapi.com 20 августа 2019 г.