Создание RESTful API с помощью Flask

Оглавление

В этом уроке мы будем изучать и создавать RESTful API с помощью Flask. Чтобы следовать этому руководству, вы уже должны хорошо знать Python, Flask и SQLAlchemy.

Поскольку приложение, которое мы будем строить в этой статье, является продолжением приложения, построенного ранее в Flask SQLAlchemy Tutorial, убедитесь, что вы уже прочитали этот пост и у вас есть код для наших дополнений к API!

Что такое API?

API - один из тех технических терминов, которыми часто бросаются в мире программирования. Мы слышим о том, как люди создают приложения, используя Uber API или Google Map API. Например, я создал приложение для поиска работы, используя API Twitter. Но что такое API и почему он так важен?

API расшифровывается как Application Programming Interface и обозначает способ взаимодействия между двумя любыми программными приложениями. API - это просто среда, позволяющая двум элементам кода общаться друг с другом.

Вы когда-нибудь внедряли Google Maps в свое приложение или видели приложение, использующее Google Maps? Это и есть Google Maps API.

Посмотрите этот учебник, чтобы увидеть Twitter API в действии:

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

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

Теперь, когда мы разобрались с API, давайте поговорим о REST.

Что такое REST?

Как и API, REST - это аббревиатура, которая расшифровывается как Representational State Transfer. Это архитектурный стиль для разработки стандартов между компьютерами, облегчающий взаимодействие систем друг с другом. Проще говоря, REST - это набор правил, которым следуют разработчики при создании API. Система называется RESTful, если она придерживается этих ограничений.

Для лучшего понимания RESTful API необходимо определить, что означают термины "клиент" и "ресурс".

Client: Под клиентом может пониматься как разработчик, так и программное приложение, использующее API. Когда вы внедряете Google Maps API в свое приложение, вы получаете доступ к ресурсам через API, что делает вас клиентом. Аналогично, клиентом может быть и веб-браузер.

Resource: Ресурс описывает объект, данные или часть информации, которую необходимо хранить или передавать другим сервисам. Например, координаты местоположения, получаемые при работе с Google Maps API, являются ресурсом.

Итак, когда клиент посылает запрос на сервер, он получает доступ к ресурсу. Но какой язык используют клиенты и серверы?

Для того чтобы люди могли разговаривать друг с другом, у нас есть соответствующий синтаксис и грамматика. Без них невозможно понять, о чем идет речь. Аналогично, API имеют набор правил для общения машин друг с другом, которые называются протоколами.

HTTP и запросы

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

При работе с RESTful API клиент отправляет HTTP-запрос, а сервер отвечает HTTP-ответом. Давайте разберемся, что представляют собой HTTP-запросы и HTTP-ответы.

Когда HTTP-запрос отправляется на сервер, он обычно содержит следующее:

  1. Заголовок
  2. Пустая строка, разделяющая заголовок и тело
  3. Необязательное тело

Заголовок состоит из HTTP-глагола, URI и номера версии HTTP, которые в совокупности называются строкой запроса.

GET /home.html HTTP/1.1

В приведенном примере GET - это HTTP-глагол, home.html - URI, откуда мы хотим получить данные, а HTTP/1.1 относится к версии HTTP.

GET - не единственный глагол HTTP, поэтому рассмотрим некоторые другие часто используемые глаголы HTTP.

  • GET: Метод GET используется только для получения информации с данного сервера. Запросы, использующие этот метод, должны только восстанавливать данные и не должны оказывать на них никакого другого влияния.
  • POST: POST-запрос используется для отправки данных обратно на сервер с помощью HTML-форм.
  • PUT: Запрос PUT заменяет все текущие представления целевого ресурса на загруженное содержимое.
  • DELETE: Запрос DELETE удаляет все текущие представления целевого ресурса, заданного URI.

Когда сервер получает запрос, он посылает сообщение обратно клиенту. В случае успешного выполнения запроса он возвращает запрошенные данные, в противном случае возвращается ошибка.

Когда HTTP-ответ отправляется обратно клиенту, он обычно содержит следующее:

  1. Заголовок
  2. Пустая строка, отделяющая заголовок от тела
  3. Необязательное тело

На этот раз заголовок содержит версию HTTP, код состояния и фразу, объясняющую код состояния на простом языке.

Вы когда-нибудь видели ошибку 404 Not Found? Это один из кодов статуса, где 404 - это код статуса, за которым следует фраза причины.

Между сервером и клиентом передается множество кодов. Некоторые из них являются следующими:

  • 200 OK: Это означает, что запрос прошел успешно
  • 201 Created: Это означает, что ресурс был создан
  • 400 Bad Request: Запрос не может быть обработан из-за плохого синтаксиса запроса
  • 404 Not Found: Это говорит о том, что сервер не смог найти запрошенную страницу

К счастью, реализация Flask сама решает большую часть этой задачи, но все же полезно знать о кодах ответов, чтобы получить максимальную отдачу от ответов API.

Создание API с помощью Flask

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

По мере роста нашей библиотеки разработчикам будет интересно ознакомиться с нашим списком или добавить новые предложенные книги. API с Flask - это как раз то, что нужно.

Создадим несколько конечных точек для базы данных books. Конечную точку можно рассматривать как место, где мы получаем доступ к определенному ресурсу API, и обычно она ассоциируется с определенной строкой URL. Но прежде чем приступить к созданию конечных точек, необходимо внести изменения в наш файл database_setup.py.

Там, где мы создали нашу таблицу Book, необходимо добавить код, возвращающий данные объекта в легко сериализуемом формате. Сериализация превратит запись в строковый формат, который можно передавать по протоколу HTTP.

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

class Book(Base):
  __tablename__ = 'book'

  id = Column(Integer, primary_key=True)
  title = Column(String(250), nullable=False)
  author = Column(String(250), nullable=False)
  genre = Column(String(250))

  @property
  def serialize(self):
     return {
        'title': self.title,
        'author': self.author,
        'genre': self.genre,
        'id': self.id,
     }

#we will save the changes and execute this script again.

В файле app.py мы добавим несколько конечных точек с помощью декоратора @app. Важно отметить, что по умолчанию @app.route имеет метод GET. Если мы хотим использовать какие-либо другие HTTP-глаголы, мы должны указать их, передав через параметр methods в виде списка.

@app.route('/')
@app.route('/booksApi', methods = ['GET', 'POST'])
def booksFunction():
   if request.method == 'GET':
       return get_books()
   elif request.method == 'POST':
       title = request.args.get('title', '')
       author = request.args.get('author', '')
       genre = request.args.get('genre', '')
       return makeANewBook(title, author, genre)

@app.route('/booksApi/', methods = ['GET', 'PUT', 'DELETE'])
def bookFunctionId(id):
   if request.method == 'GET':
       return get_book(id)
 
   elif request.method == 'PUT':
       title = request.args.get('title', '')
       author = request.args.get('author', '')
       genre = request.args.get('genre', '')
       return updateBook(id,title, author,genre)
  
   elif request.method == 'DELETE':
       return deleteABook(id)

Мы создали две функции booksFunction и bookFunctionId(id). Первая функция оценивает, является ли метод запроса GET или POST. Если первый, то она возвращает метод get_books. В противном случае будет возвращен метод makeANewBook.

Функция makeANewBook() принимает три параметра. Это значения, необходимые нам для создания строки в таблице нашей базы данных.

Вторая наша функция, bookFunctionId(), также проверяет наличие GET-запроса. Между GET-запросом в booksFunction и bookFunctionId есть небольшое различие. GET-запрос в первой функции возвращает все книги в нашей базе данных, а GET-запрос во второй функции возвращает только отфильтрованную книгу.

Функция bookFunctionId() также оценивает для методов PUT и DELETE и возвращает соответственно updateBook() и deleteABook().

from Flask import jsonify
def get_books():
   books = session.query(Book).all()
   return jsonify(books= [b.serialize for b in books])

def get_book(book_id):
   books = session.query(Book).filter_by(id = book_id).one()
   return jsonify(books= books.serialize)

def makeANewBook(title,author, genre):
   addedbook = Book(title=title, author=author,genre=genre)
   session.add(addedbook)
   session.commit()
   return jsonify(Book=addedbook.serialize)

def updateBook(id,title,author, genre):
   updatedBook = session.query(Book).filter_by(id = id).one()
   if not title:
       updatedBook.title = title
   if not author:
       updatedBook.author = author
   if not genre:
       updatedBook.genre = genre
   session.add(updatedBook)
   session.commit()
   return 'Updated a Book with id %s' % id

def deleteABook(id):
   bookToDelete = session.query(Book).filter_by(id = id).one()
   session.delete(bookToDelete)
   session.commit()
   return 'Removed Book with id %s' % id

Вверху мы импортируем jsonify из Flask функцию, которая сериализует переданные ей данные в JSON. Сериализация данных преобразует структурированные данные в формат, позволяющий совместно использовать или хранить данные в их исходной структуре.

До того как JSON стал популярным, для открытого обмена данными широко использовался XML. JSON требует меньше накладных расходов при разборе, поэтому его чаще можно встретить при взаимодействии с API через Python.

Здесь мы создаем пять различных функций, выполняющих CRUD-операции. Чтобы создать новую книгу, мы вставляем новые значения в таблицу Book. Для чтения существующих книг из нашей базы данных мы используем функцию all(). Чтобы обновить книгу в нашей базе данных, мы сначала находим ее, обновляем значения и добавляем их. И, наконец, чтобы удалить книгу, мы сначала находим ее, а затем просто вызываем delete() и фиксируем изменение.

Проверка конечных точек с помощью Postman

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

После установки Postman приступим к тестированию конечных точек. В этой статье мы будем тестировать только запросы GET и POST.

Сначала выполним наш app.py файл. Чтобы проверить, все ли работает, попробуем выполнить запрос GET. Из выпадающего меню выберем GET и пошлем запрос по адресу http://localhost:4996/booksApi. Вы должны увидеть нечто похожее на следующее изображение:

Для тестирования нашего POST запроса мы выберем POST из выпадающего меню. Затем мы обновим наши значения, используя предоставленные формы значений ключей. При вводе обновленных значений обратите внимание на то, как автоматически обновляется наш URL.

После обновления значения мы снова нажмем кнопку send - и вуаля! Мы успешно добавили новую книгу. Вы можете проверить это, снова отправив запрос GET, и ваша новая книга должна появиться в списке.

Заключение

Мы только что создали веб-приложение на Flask, которое предоставляет REST API для нашего приложения для отслеживания книг. Как видите, написание RESTful API не представляет собой ничего сложного. Теперь у вас есть представление о том, как написать RESTful API с помощью Flask.

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

Python и Flask - при желании с использованием SQLAlchemy для работы с базой данных - являются прекрасными инструментами, позволяющими ответить на эти и другие вопросы, а также сообщества Python и Open Source.

Вернуться на верх