Как сделать свой api на python
Рассмотренного в прошлых темах материала достаточно для создания примитивного приложения. В этой теме попробуем реализовать простейшее приложение Web API в стиле REST. Архитектура REST предполагает применение следующих методов или типов запросов HTTP для взаимодействия с сервером, где каждый тип запроса отвечает за определенное действие:
- GET (получение данных)
- POST (добавление данных)
- PUT (изменение данных)
- DELETE (удаление данных)
Для каждого из этих типов запросов класс FastAPI предоставляет соответствующие методы. Рассмотрим, как мы можем реализовать с помощью этих методов простейший API. Пусть у нас будет следующий проект:
Создание сервера
В файле main.py определим следующий код:
import uuid from fastapi import FastAPI, Body, status from fastapi.responses import JSONResponse, FileResponse class Person: def __init__(self, name, age): self.name = name self.age = age self.id = str(uuid.uuid4()) # условная база данных - набор объектов Person people = [Person("Tom", 38), Person("Bob", 42), Person("Sam", 28)] # для поиска пользователя в списке people def find_person(id): for person in people: if person.id == id: return person return None app = FastAPI() @app.get("/") async def main(): return FileResponse("public/index.html") @app.get("/api/users") def get_people(): return people @app.get("/api/users/") def get_person(id): # получаем пользователя по id person = find_person(id) print(person) # если не найден, отправляем статусный код и сообщение об ошибке if person==None: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content= < "message": "Пользователь не найден" >) #если пользователь найден, отправляем его return person @app.post("/api/users") def create_person(data = Body()): person = Person(data["name"], data["age"]) # добавляем объект в список people people.append(person) return person @app.put("/api/users") def edit_person(data = Body()): # получаем пользователя по id person = find_person(data["id"]) # если не найден, отправляем статусный код и сообщение об ошибке if person == None: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content= < "message": "Пользователь не найден" >) # если пользователь найден, изменяем его данные и отправляем обратно клиенту person.age = data["age"] person.name = data["name"] return person @app.delete("/api/users/") def delete_person(id): # получаем пользователя по id person = find_person(id) # если не найден, отправляем статусный код и сообщение об ошибке if person == None: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content= < "message": "Пользователь не найден" >) # если пользователь найден, удаляем его people.remove(person) return person
Разберем в общих чертах этот код. Прежде всего для представления данных, с которыми мы будем работать, определяем класс Person .
class Person: def __init__(self, name, age): self.name = name self.age = age self.id = str(uuid.uuid4())
Этот класс содержит три атрибута. Два атрибута — name и age будут представлять имя и возраст пользователя и будут устанавливаться через конструктор. А третий атрибут — id будет служить для уникальной идентификации данного объекта и будет хранить значение guid. Для генерации guid применяется функция uuid.uuid4() из пакета uuid . В конструкторе Person сгенерированный guid преобразуется в строку и присваивается атрибуту id.
Для хранения данных в приложении определим список people, который будет выполнять роль условной базы данных и будет хранить объекты Person.
people = [Person("Tom", 38), Person("Bob", 42), Person("Sam", 28)]
Для поиска объекта Person в этом списке определена вспомогательная функция find_person() .
При обращении к корню веб-приложения, то есть по пути «/», оно будет отправлять в ответ файл index.html , то есть веб-страницу, посредством которой пользователь сможет взаимодействовать с сервером:
@app.get("/") def main(): return FileResponse("public/index.html")
Далее определяются функции, которые собственно и представляют API. Вначале определяется функция, которая обрабатывает запрос типа GET по пути «api/users»:
@app.get("/api/users") def get_people(): return people
Запрос GET предполагает получение объектов, и в данном случае отправляем выше определенный список объектов Person.
Когда клиент обращается к приложению для получения одного объекта по id в запрос типа GET по адресу «api/users/», то срабатывает другая функция:
@app.get("/api/users/") def get_person(id): person = find_person(id) if person==None: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content= < "message": "Пользователь не найден" >) return person
Здесь через параметр id получаем из пути запроса идентификатор объекта Person и по этому идентификатору ищем нужный объект в списке people. Если объект по id не был найден, то возвращаем с помощью класса JSONResponse статусный код 404 с некоторым сообщением в формате JSON. Если объект найден, то отправляем найденный объект клиенту.
При получении запроса типа DELETE по маршруту «/api/users/» срабатывает другая функция:
@app.delete("/api/users/") def delete_person(id): person = find_person(id) if person == None: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content= < "message": "Пользователь не найден" >) people.remove(person) return person
Здесь действует аналогичная логика — если объект по id не найден, отправляет статусный код 404. Если же объект найден, то удаляем его из списка и посылаем клиенту.
При получении запроса с методом POST по адресу «/api/users» срабатывает следующая функция:
@app.post("/api/users") def create_person(data = Body()): person = Person(data["name"], data["age"]) people.append(person) return person
Запрос типа POST предполагает передачу приложению отправляемых данных. Причем мы ожидаем, что клиент отправит данные, которые содержат значения name и age. Для краткости мы пока опускаем валидацию входных данных. И для получения данных из тела запроса с помощью класса Body получаем данные в параметр data и затем используем данные из этого параметра для создания объекта Person. Затем созданный объект добавляется в список people и отправляется назад клиенту.
Если приложению приходит PUT-запрос по адресу «/api/users», то аналогичным образом получаем отправленные клиентом данные в виде объекта Person и пытаемся найти подобный объект в списке people. Если объект не найден, отправляем статусный код 404. Если объект найден, то изменяем его данные и отправляем обратно клиенту:
@app.put("/api/users") def edit_person(data = Body()): person = find_person(data["id"]) if person == None: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content= < "message": "Пользователь не найден" >) person.age = data["age"] person.name = data["name"] return person
Таким образом, мы определили простейший API. Теперь добавим код клиента.
Определение клиента
Теперь в проекте определим папку public , в которую добавим новый файл index.html
Определим в файле index.html следующим код для взаимодействия с сервером FastAPI:
METANIT.COM td buttonСписок пользователей
Имя:
Возраст:
| Имя | Возраст |
|---|
Основная логика здесь заключена в коде javascript. При загрузке страницы в браузере получаем все объекты из БД с помощью функции getUsers() :
async function getUsers() < // отправляет запрос и получаем ответ const response = await fetch("/api/users", < method: "GET", headers: < "Accept": "application/json" >>); // если запрос прошел нормально if (response.ok === true) < // получаем данные const users = await response.json(); const rows = document.querySelector("tbody"); // добавляем полученные элементы в таблицу users.forEach(user =>rows.append(row(user))); > >
Для добавления строк в таблицу используется функция row() , которая возвращает строку. В этой строке будут определены ссылки для изменения и удаления пользователя.
Ссылка для изменения пользователя с помощью функции getUser() получает с сервера выделенного пользователя:
async function getUser(id) < const response = await fetch(`/api/users/$`, < method: "GET", headers: < "Accept": "application/json" >>); if (response.ok === true) < const user = await response.json(); document.getElementById("userId").value = user.id; document.getElementById("userName").value = user.name; document.getElementById("userAge").value = user.age; >else < // если произошла ошибка, получаем сообщение об ошибке const error = await response.json(); console.log(error.message); // и выводим его на консоль >>
И выделенный пользователь добавляется в форму над таблицей. Эта же форма применяется и для добавления объекта. С помощью скрытого поля, которое хранит id пользователя, мы можем узнать, какое действие выполняется — добавление или редактирование. Если id не установлен (равен пустой строке), то выполняется функция createUser, которая отправляет данные в POST-запросе:
async function createUser(userName, userAge) < const response = await fetch("api/users", < method: "POST", headers: < "Accept": "application/json", "Content-Type": "application/json" >, body: JSON.stringify(< name: userName, age: parseInt(userAge, 10) >) >); if (response.ok === true) < const user = await response.json(); document.querySelector("tbody").append(row(user)); >else < const error = await response.json(); console.log(error.message); >>
Если же ранее пользователь был загружен на форму, и в скрытом поле сохранился его id, то выполняется функция editUser, которая отправляет PUT-запрос:
async function editUser(userId, userName, userAge) < const response = await fetch("api/users", < method: "PUT", headers: < "Accept": "application/json", "Content-Type": "application/json" >, body: JSON.stringify(< id: userId, name: userName, age: parseInt(userAge, 10) >) >); if (response.ok === true) < const user = await response.json(); document.querySelector(`tr[data-rowid='$']`).replaceWith(row(user)); > else < const error = await response.json(); console.log(error.message); >>
И функция deleteUser() посылает на сервер запрос типа DELETE на удаление пользователя, и при успешном удалении на сервере удаляет объект по id из списка объектов Person.
Теперь запустим проект, и по умолчанию приложение отправит браузеру веб-страницу index.html , которая загрузит список объектов:

После этого мы сможем выполнять все базовые операции с пользователями — получение, добавление, изменение, удаление. Например, добавим нового пользователя:
Как создать RESTful API на Python
Узнайте, как создать RESTful API на Python с использованием Flask, для легкого взаимодействия с системами и сервисами.

Алексей Кодов
Автор статьи
23 июня 2023 в 18:42
Создание RESTful API на Python является важным навыком для любого разработчика, поскольку API играют центральную роль в современных веб-приложениях. В этой статье мы рассмотрим основы создания RESTful API с использованием Python и популярного фреймворка Flask.
Что такое RESTful API?
RESTful API (Representational State Transfer) — это архитектурный стиль, который определяет набор ограничений для создания веб-сервисов. RESTful API позволяют разработчикам легко взаимодействовать с различными системами и сервисами, используя стандартные HTTP-методы, такие как GET, POST, PUT и DELETE.
Подготовка окружения
Для начала установим фреймворк Flask:
pip install Flask
Теперь создадим новый файл app.py и импортируем необходимые модули:
from flask import Flask, jsonify, request app = Flask(__name__)
В этом примере мы используем функцию jsonify для преобразования словаря Python в JSON-объект.
Создание маршрутов
Для создания RESTful API нам нужно определить маршруты, которые будут обрабатывать HTTP-запросы. Воспользуемся декоратором @app.route для определения маршрутов:
@app.route('/api/v1/tasks', methods=['GET']) def get_tasks(): tasks = [ , ] return jsonify()
Здесь мы определили конечную точку /api/v1/tasks с HTTP-методом GET. Эта функция возвращает список задач в формате JSON.
Python-разработчик: новая работа через 9 месяцев
Получится, даже если у вас нет опыта в IT

Запуск приложения
Чтобы запустить наше приложение, добавим следующий код в конец файла app.py :
if __name__ == '__main__': app.run(debug=True)
Теперь, когда мы запустим наше приложение командой python app.py , оно будет доступно по адресу http://127.0.0.1:5000 .
Расширение API
Мы можем расширить наш API, добавив функциональность создания, обновления и удаления задач. Для этого добавим новые маршруты и соответствующие функции:
@app.route('/api/v1/tasks', methods=['POST']) def create_task(): # Здесь будет код для создания задачи @app.route('/api/v1/tasks/<int:task_id>', methods=['PUT']) def update_task(task_id): # Здесь будет код для обновления задачи @app.route('/api/v1/tasks/<int:task_id>', methods=['DELETE']) def delete_task(task_id): # Здесь будет код для удаления задачи
Не забывайте протестировать ваш API с помощью инструментов, таких как Postman или curl.
В заключение, создание RESTful API на Python с использованием Flask — относительно простая задача. Следуя приведенным выше примерам, вы сможете создать собственное API для ваших проектов. Удачи в разработке!
Пишем свой REST API на Python с Flask: подробный guide

Как значения из форм браузера попадают в базу данных, в чем разница между телом и параметрами запроса и каким образом таблица БД связана с классом ООП-скрипта: пишем REST API своего веб-приложения на Python с СУБД SQLLite, фреймворком Flask и тестированием в Postman.
Проектирование REST API
Чтобы на своем курсе по основы архитектуры и интеграции информационных систем показать, как работать с REST-приложениями, включая вызовы HTTP-методов через Postman и элементы веб-интерфейса, я написала свой API на Python, используя фреймворк быстрой разработки приложений Flask. В качестве примера возьмем сервис управления клиентскими заявками, который предоставляет следующие функциональные возможности:
- отправить заявку на курс с указанием имени клиента, адреса его электронной почты и номера телефона;
- просмотреть отдельно взятую заявку;
- просмотреть весь список имеющихся заявок;
- изменить заявку;
- удалить заявку.
Это типичные CRUD-операции, которые отлично реализуются в архитектурном стиле REST. Клиентская заявка представлена следующей структурой данных:
| Поле | Смысл | Nullable (может быть не задано пользователем) | Тип данных |
| course | Курс, на который подается заявка. Значение выбирается из заранее заданного набора курсов (OAIS, TTIS, BUML) | нет | Строка (str) |
| name | Имя клиента | Да | Строка (str) |
| Адрес электронной почты клиента, можно проверять по шаблону xxx@xxx.xxx | Да | Строка (str) | |
| phone | Телефон клиента | Да | Строка (str) |
| id | Идентификатор клиентской заявки, присваивается автоматически, а не задается пользователем | да | Целое число (Int) |
В виде JSON-документа клиентская заявка представляется так:
- клиент (слой представления, фронтэнд) в виде браузера обращается к серверной части (бэкенду) не напрямую, а через веб-сервер (в моем случае Uvicorn — реализация веб-сервера ASGI для Python);
- веб-сервер принимает HTTP-запросы от клиентов, обогащает их, маршрутизирует к серверному веб-приложению и выдает клиентам полученные от бэкенда HTTP-ответы;
- серверное веб-приложение обращается к базе данных, направляя соответствующий SQL-запрос по предварительно настроенному подключению;
Чтобы сэкономить время, в качестве базы данных я решила использовать встроенную в Python легковесную SQLite — библиотеку, которая предоставляет облегченную базу данных на диске, не требующую отдельного серверного процесса. Она позволяет обращаться к базе данных с через SQL-запросы и может использоваться Python-приложениями для внутреннего хранения данных. Разумеется, много данных в ней не сохранить, но для демонстрационного примера это и не нужно.
Поскольку цель этого сервиса – научить начинающих аналитиков работать с REST API через инструмент тестирования Postman, я решила реализовать представленные выше функциональные требования в нескольких интерфейсах: через GUI в клиентском браузере и Postman. Причем изменение заявки возможно через отправку данных как в теле PUT-запроса, так и в параметрах, т.е. в адресной строке URL после знака вопроса (?). Чтобы резюмировать проектируемый REST API, сопоставим функциональные требования (ФТ) к веб-сервису с конечными точками (endpoint) и HTTP-запросами:
Поскольку я все-таки не разработчик и не часто пишу код, разворачивать полноценную IDE на своем компьютере пока кажется нецелесообразным. Под мои задачи проверки гипотез и быстрого прототипирования вполне хватает возможностей интерактивной среды Google Colab. В этот раз я буду пользоваться ей снова, чтобы запустить скрипт своего Python-приложения, код которого рассмотрим далее.
Разработка ТЗ на информационную систему по ГОСТ и SRS
Код курса
TTIS
Ближайшая дата курса
4 декабря, 2023
Длительность обучения
12 ак.часов
Стоимость обучения
20 000 руб.
Реализация на Python в Google Colab
Возвращаясь к моему Pуthon-приложению, запущенному в Google Colab, чтобы получить доступ к нему, нужно использовать веб-сервер, домен, хостинг и пр. Напомню, веб-сервер позволяет обращаться к серверному веб-приложению по протоколам HTTP и HTTPS, поддерживая HTTP-стандарты. Чтобы не тратить время и силы на настройку веб-сервера, я снова воспользуюсь утилитой ngrok, которая позволяет поделиться локальным сервером разработки localhost, создав безопасный туннель с внешнего URL-адреса на локальный компьютер.
Утилита ngrok запускает на локальном компьютере небольшой клиентский процесс, который создает частный туннель подключения к облачной службе ngrok. Локальный сервер разработки localhost сопоставляется с поддоменом ngrok.io, к которому может получить доступ удаленный пользователь. При этом не нужно открывать порты, настраивать пересылки и выполнять прочие действия системного администратора, сложные для большинства аналитиков.
Чтобы воспользоваться возможностями Flask и uvicorn – удаленного веб-сервера для Python, в блокноте Google Colab, сперва следует установить их. Впрочем, для работы мне понадобились не только эти библиотеки, но и другие пакеты, например, Pydantic — библиотека на основе классов данных Python, добавляющая дополнительные функции для валидации и анализа данных. Именно Pydantic предоставляет специальный класс BaseModel, который я использую для определения модели данных клиентской заявки и правил проверки некоторых полей этого класса, таких как email. Чтобы сохранять заявки во встроенную базу данных SQLlite, нужно импортировать библиотеку sqlite3, а также модули многопоточной работы с базой данных и трассировки ошибок. Полный перечень необходимых зависимостей, т.е. устанавливаемых библиотек и импортируемых пакетов показан в следующем участке кода, который надо запускать в отдельной ячейке Google Colab:
#############################ячейка №1 в Google Colab########################################################### # Установка необходимых библиотек !pip install flask !pip install flask-ngrok !pip install fastapi nest-asyncio pyngrok uvicorn !pip install pydantic[email] # Импорт модулей и библиотек import traceback import threading from flask_ngrok import run_with_ngrok from flask import Flask, jsonify, request, render_template, Response from pydantic import BaseModel, EmailStr, ValidationError from enum import Enum from typing import Union, Optional, List import os import sqlite3 import tkinter as tk
За визуальную часть моего приложения отвечают 3 HTML-страницы, которые будут использоваться в качестве шаблонов, лежащих в директории templates в пространстве пользователя Colab в течение длительности сеанса:

В отдельной ячейке Colab пишем код для создания директории для хранения HTML-страниц:
#############################ячейка №2 в Google Colab########################################################### # создаем директорию с шаблонами !mkdir templates
В следующих 3-х ячейках пишем фронтэнд, т.е. создаем сами HTML-страницы для GUI:
#############################ячейка №3 в Google Colab########################################################### # создаем html-страницу добавления заявки %%writefile templates/index.htmlСервис управления заявками Сервис управления заявками
| Отправить новую заявку |
| Смотреть все заявки |
Отправить заявку
| ГЛАВНАЯ | Все заявки | Добавить заявку |
