Пишемо API на Python (з Flask та RapidAPI)

Пишемо API на Python (з Flask та RapidAPI)

Якщо ви читаєте цю статтю, ймовірно, ви вже знайомі з можливостями, які відкриваються під час використання API (Application Programming Interface).

Додавши в свою програму один з багатьох відкритих API, ви можете розширити функціональність цієї програми або доповнити його потрібними даними. Але що якщо ви розробили унікальну функцію, якою хочете поділитися з ком'юніті?

Відповідь проста: потрібно створити власний API.

Незважаючи на те, що це спершу здається складним завданням, насправді все просто. Ми розповімо, як це зробити за допомогою Python.

Що потрібно для початку роботи

Для розробки API необхідні:

  • Python 3;
  • Колба - Простий і легкий у використанні фреймворк для створення веб-додатків;
  • Колба-СПОЧ - Розширення для Flask, яке дозволяє розробити REST API швидко і з мінімальним налаштуванням.

Установка виконується командою:

pip install flask-restful

Рекомендуємо безкоштовний інтенсив програмування для початківців:
Розробка telegram-бота на C# - 26-28 серпня. Безкоштовний інтенсив, який дозволяє розібратися в тому, як працюють роботи-помічники, в особливостях роботи з API Telegram та інших нюансах. Троє найкращих учасників отримають від Skillbox 30 000 рублів.

Перед початком

Ми збираємося розробити RESTful API з базовою CRUID-функціональністю.

Щоб повністю зрозуміти завдання, розберемося з двома термінами, згаданими вище.

Що таке REST?

REST API (Representational State Transfer) – це API, яке використовує HTTP-запити для обміну даними.

REST API повинні відповідати певним критеріям:

  • Архітектура клієнт-сервер: клієнт взаємодіє з інтерфейсом користувача, а сервер - з бекендом і сховищем даних. Клієнт та сервер незалежні, будь-який з них може бути замінений окремо від іншого.
  • Stateless — жодні дані клієнта не зберігаються на сервері. Стан сеансу зберігається за клієнта.
  • Кешування - клієнти можуть кешувати відповіді сервера для поліпшення загальної продуктивності.

Що таке CRUD?

Сирий — концепція програмування, яка описує чотири базові дії (create, read, update та delete).

У REST API типи запитів та методи запиту відповідають такі дії, як post, get, put, delete.

Тепер, коли ми розібралися з базовими термінами, можна розпочати створення 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 для відображення випадкової цитати.

Тепер ми створимо репозиторій цитат про ІІ.

Кожен запис репо міститиме:

  • цифровий ID;
  • ім'я автора цитати;
  • цитати.

Оскільки це лише приклад для навчання, ми збережемо всі записи у списку 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, post, put, delete.

Почнемо з методу 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. Якщо нічого не знайдено, виводиться повідомлення “Quote not found, 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, він отримав автора і цитату із запиту, зберігши їх у словнику params.

Якщо цитата із зазначеним ID вже існує, то метод виводить відповідне повідомлення та код 400.

Якщо цитата із зазначеним ID ще не була створена, метод створює новий запис із зазначеним ID та автором, а також іншими параметрами. Потім він додає запис до списку 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 і input і парсить параметри цитати, використовуючи reqparse.

Якщо цитата із зазначеним ID існує, метод оновить її з новими параметрами, а потім виведе оновлену цитату з кодом 200. Якщо цитати із зазначеним ID ще немає, буде створено новий запис із кодом 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

Цей метод отримує ID цитати під час введення та оновлює список ai_quotes, використовуючи загальний список.

Тепер, коли ми створили всі методи, все, що нам потрібно, просто додати resource до API, задати шлях і запустити Flask.

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

Наш REST API Service готовий!

Далі ми можемо зберегти код у файл app.py, запустивши його в консолі за допомогою команди:

python3 app.py

Якщо все добре, то ми отримаємо щось на кшталт цього:

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

Тестуємо API

Після того, як API створено, його потрібно протестувати.

Зробити це можна за допомогою консольної утиліти curl або клієнта Insomnia REST або опублікувавши API на Rapid API.

Пишемо API на Python (з Flask та RapidAPI)

Публікуємо наш API

RapidAPI — найбільший у світі маркетплейс із більш ніж 10 000 API (і близько 1 млн розробників).

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

Для того щоб зробити цеспочатку потрібно опублікувати його на якомусь сервері в мережі. У нашому випадку скористаємося Heroku. Робота з ним не повинна викликати жодних складнощів, (дізнатися про нього більше можна тут).

Як опублікувати ваш API на Heroku

1. Встановлюємо Heroku.

Насамперед потрібно зареєструватися та встановити Heroku Command Line Interface (CLI). Це працює на Ubuntu 16+.

sudo snap install heroku-classic

Потім логінимся:

вхід у heroku

2. Додаємо необхідні файли.

Тепер потрібно додати файли для публікації до папки в нашому додатку:

  • requirements.txt зі списком необхідних Python модулів;
  • Procfile, який вказує, які команди повинні бути виконані для запуску програми;
  • .gitignore — щоб виключити файли, які не потрібні на сервері.

Файл requirements.txt міститиме наступні рядки:

  • колбу
  • flask-restful
  • руж'я

Будь ласка, зверніть увагу: ми додали 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

Відправляємо master branch у віддалений репо Heroku:

git push heroku master

Тепер можна розпочати, відкривши API Service за допомогою команд:

heroku ps:scale web=1
heroku open
 

API буде доступно за адресою your-random-heroku-name.herokuapp.com/ai-quotes.

Як додати ваш Python API у маркетплейс RapidAPI

Після того, як API-сервіс опублікований на Heroku, можна додати його до Rapid API. Тут докладна документація по цій темі.

1. Створюємо обліковий запис RapidAPI.

Пишемо API на Python (з Flask та RapidAPI)

Реєструємо безкоштовний обліковий запис - це можна зробити за допомогою Facebook, Google, GitHub.

Пишемо API на Python (з Flask та RapidAPI)

2. Додаємо API до панелі керування.

Пишемо API на Python (з Flask та RapidAPI)

3. Далі вводимо загальну інформацію про API.

Пишемо API на Python (з Flask та RapidAPI)

4. Після натискання Add API з'являється нова сторінка, де можна ввести інформацію про наш API.

Пишемо API на Python (з Flask та RapidAPI)

5. Тепер можна або вручну ввести ендпоінти API, або завантажити swagger-file за допомогою OpenAPI.

Пишемо API на Python (з Flask та RapidAPI)

Ну, а тепер потрібно задати ендпоінти нашого API на сторінці Endpoints. У нашому випадку ендпоїнти відповідають концепції CRUD (get, post, put, delete).

Пишемо API на Python (з Flask та RapidAPI)

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

Для створення ендпоінту потрібно натиснути кнопку Create Endpoint.

Пишемо API на Python (з Flask та RapidAPI)

Повторюємо цей процес для всіх інших ендпоінтів API. На цьому все! Вітаю, ви опублікували ваш API!

Якщо все добре, сторінка API виглядатиме якось так:

Пишемо API на Python (з Flask та RapidAPI)

Висновок

У цій статті ми вивчили процес створення власного RESTful API Service на Python, разом із процесом публікації API у хмарі Heroku та додаванням його до каталогу RapidAPI.

Але в тестовому варіанті були показані лише базові принципи розробки API — такі нюанси, як безпека, стійкість до відмов і масштабованість, не розглядалися.

Під час розробки реального API усе це потрібно враховувати.

Джерело: habr.com

Додати коментар або відгук