<style> .reveal { font-size: 28px; } /* .reveal p { text-align: left; } */ .reveal section img { background:none; border:none; box-shadow:none; } /* .reveal .polina { border:10; } */ </style> # Web сервисы, фреймворки, API <!-- [v1] --> Белов Виталий, весна 2021 [TOC] --- # API *Application Programming Interface* Это способ коммуникации програмных компонентов ![](https://i.imgur.com/JFr6Imq.png) - Внутренние API (собственных библиотек) - для коммуникации микросервисов внутри приложения/компании - Внешние API (веб-сервисов) - позволяют получить доступ к сервису сторонним разработчикам через интернет, используя HTTP или другие протоколы Как согласовать различные API? - *REST* и *RPC* --- ## REST - Как расшифровывается? - **RE**presentational **S**tate **T**ransfer - Что это? - Набор [правил](http://www.restapitutorial.ru/lessons/whatisrest.html#uniform-interface), которые позволяют разного рода системам обмениваться данными и масштабировать приложение. Соответствие этим правилам - нестрогое - Как? - Используется HTTP протокол - прикладной уровень обмена данными по сети Если при проектировании правила REST соблюдены - такой протокол называется *RESTful* ---- RESTful API позволяет производить CRUD операции над всеми объектами, представленными в системе. *CRUD* - <!--концепция программирования-->аббревиатура, которая описывает четыре базовых действия - C - create - R - read - U - update - D - delete Пример CRUD API: ![](https://i.imgur.com/IrwHLYf.png) <!-- Также вводится понятие **ресурса**: Когда вы решаете, какие ресурсы буду в вашей системе, называйте их существительными. Другими словами, URI должен ссылаться на ресурс, а не на действие. Примеры ресурсов: - Пользователи системы. - История сообщений пользователя. --> ---- <!-- ### REST API ![](https://i.imgur.com/U5y9wFQ.png =150x) --> <!-- [Задание](https://starkovden.github.io/workshop-activities.html) --> Конечная точка (*endpoint*) - это ресурс, расположенный на веб-сервере по определенному пути. Endpoint приложения может выглядеть так: ![](https://i.imgur.com/Hn5zQu8.png) ---- В REST API CRUD соответствуют *post*, *get*, *put*, *delete*. Ответ (Response) возвращается, как правило, в формате JSON или XML(реже). ![](https://i.imgur.com/DZak8uf.png =500x) https://www.youtube.com/watch?v=LooL6_chvN4 --- - **get** - вернуть список объектов: Request: ```shell GET /api/train_samples ``` Response: ```shell [ {id:0, password: 'qwerty', times: 1601}, {id:1, password: 'admin', times: 1920} ... ] ``` ---- - **post** - добавить объект: Request: ```shell POST /api/train_samples/ ``` Request object: ```shell {password: '0000', times: 1000} ``` Response: ```python {id:9, password: '0000', times: 1000} ``` id - назначится сам ---- - **put** - обновить выбранную запись: Request: ```shell PUT /api/train_samples/1 ``` Request object: ```shell {id:1, password: 'admin', times: 2000} ``` Response: ```shell {id:1, password: 'admin', times: 2000} ``` ---- - **delete** - удалить выбранный объект: Request: ```shell DELETE /api/train_samples/1 ``` :::info :pushpin: [Еще пример описания API метода](https://gist.github.com/iros/3426278) ::: --- ## Коды ответов | Код | Название | Описание | | -------- | -------- | -------- | | 200 | OK | Запрос выполнен успешно | | 201 | Created | Возвращается при каждом создании ресурса в коллекции| | 204 | No Content | Нет содержимого. Это ответ на успешный запрос, например, после DELETE) | - https://habr.com/ru/post/440900/ - статья про коды и REST - https://developer.mozilla.org/ru/docs/Web/HTTP/Status - полная таблица кодов ---- | Код | Название | Описание | | -------- | -------- | -------- | | 400 | Bad Request | Ошибка на стороне Клиента. Например, неправильный синтаксис запроса, неверные параметры запроса и т.д.| | 401 | Unauthorized | Клиент пытается работать с закрытым ресурсом без предоставления данных авторизации | | 403 | Forbidden | Сервер понял запрос, но отказывается его обрабатывать | | 404 | Not found | Запрашивается несуществующий ресурс | | 405 | Method Not Allowed | Клиент пытался использовать метод, который недопустим для ресурса. Например, указан метод DELETE, но такого метода у ресурса нет| | 500 | Server error|Общий ответ об ошибкtе на сервере, когда не подходит никакой другой код ошибки| --- ## Curl <!-- https://flaviocopes.com/http-curl/ --> - Что это? - Client URL, утилита командной строки - Зачем? - позволяет выполнять запросы с различными параметрами и методами без перехода к веб-ресурсам в адресной строке браузера. Поддерживает протоколы HTTP, HTTPS, FTP, FTPS, SFTP и др. ---- ### Установка * В MacOS, Ubuntu - доступен из командной строки * В Windows - требуется установка. [Инструкция](http://www.confusedbycode.comg/curl/#downloads). Можно также установить Git Bush. Проверить установку в WIN можно из командной строки *cmd* ➜ *curl -V* Если установлен, появится сообщение вида: `curl 7.55.1 (Windows) libcurl/7.55.1 WinSSL` ---- ### Примеры запросов * **Curl - GET запрос** ```curl curl https://host.com ``` Метод GET - по умолчанию. Тот же результат получим, если вызовем так: ```curl curl -X GET https://host.com ``` Чтобы получить ответ с заголовком: ```curl curl https://host.com -i ``` Ответ будет содержать версию HTTP, код и статус ответа (например: HTTP/2 200 OK). Затем заголовки ответа, пустая строка и тело ответа. ---- * **Curl - POST запрос** ```curl curl -X POST https://host.com ``` Используя передачу данных (URL-encoded): ```curl curl -d "option=value_1&something=value_2" -X POST https://host.com/ ``` Здесь -d или --data - флаг, обозначающий передачу данных ---- * **POST запрос, используя формат JSON** ```curl curl -d '{"option": "val"}' -H "Accept:application/json" -X POST https://host.com/ ``` Здесь -H или --header - флаг заголовока запроса на ресурс Или можно передать json, как файл: ```curl curl -d "@file.json" -X POST https://host.com/ ``` ---- **Еще флаги:** * `-u user:pass` - если на сервере требуется аутентификация * `curl -verbose`, отображает подробности * `-L`, поддержка redirect (если ресурс перемещен) * `-O` - cохранить с тем же именем, -o data.json - со новым именем <!--https://starkovden.github.io/understand-curl.html--> [Документация](https://curl.se/docs/manpage.html) --- ## Недостатки/особенности REST API: * Для каждого языка необходимость разработки своего API. (Можно использовать Swagger - рассмотрим далее) * JSON для передачи данных - не бинарный формат. Медленнее передача данных, но удобнее просматривать данные * Протокол HTTP 1.1 - не поддерживает передачу потоковых данных Данные недостатки учтены в **gRPC(Google Remote Procedure Call)** ---- <!-- --- ## gPRC Саша: закомментил, думаю, нам не надо про это рассказывать --> ## gRPC Основан на **RPC** - вызове удаленного кода на других машинах. ![](https://i.imgur.com/BxyZuSA.png =280x) **Отличия:** * Генерация кода стандартными средствами. Используется компилятор **Protoc**, который генерирует код для множетсва языков, включая python * Бинарный формат данных **Protobuf**, использует сжатие -> быстрее передача данных * Протокол HTTP 2 (2015 год) -> потоковая передача данных, бинарный формат, выше скорость и пр. ---- **Что выбрать?:** * Если важна скорость - gRPC * Если монолитное приложение с доступом извне или браузер - REST API * Распределенная система на микросервисах - gRPC * Потоковые данные (например, с датчиков) - gRPC [Быстрый старт и руководство gRPC для Python](https://grpc.io/docs/languages/python/) --- ## Open API ![](https://i.imgur.com/Ou2JKbZ.png =150x) Общепринятым форматом для описания REST API на сегодняшний день является OpenAPI, который также известен как Swagger Cпецификация представляет из себя единый файл в формате JSON или YAML, состоящий из трёх разделов: 1. Заголовок, содержащий название, описание и версию API, а также дополнительную информацию; 2. Описание всех ресурсов, включая их идентификаторы, HTTP-методы, все входные параметры, а также коды и форматы тела ответов; 3. Определения объектов в формате JSON Schema, которые могут использоваться как во входных параметрах, так и в ответах. --- # Веб-фреймворки ## Flask ![](https://i.imgur.com/yw7LlOi.png =100x) Что это? - Веб-фреймворк для Python Почему выбираем его по-умолчанию? - Минималистичный фреймворк - Быстрое прототипирование - Низкоуровневый фреймворк, после освоения будет проще разобраться с Django Также, лучшим решением будет выбрать Flask, если: * Разрабатывается микросерсисная архитектура * Реализуется REST API без фронтенда * Требуется гибкая кастомизация <!-- https://flask-restplus.readthedocs.io/en/stable/index.html https://buildmedia.readthedocs.org/media/pdf/flask-russian-docs/latest/flask-russian-docs.pdf https://flask-russian-docs.readthedocs.io/ru/latest/quickstart.html#debug-mode --> ---- ### Minimal Flask App ```python= from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!' if __name__ == '__main__': app.run() ``` Запустив приложение, получим соообщение: ```bash= ~ python app.py Running on http://127.0.0.1:5000/ ``` Localhost - c IP адресом 127.0.01 ➜ внутренняя сеть компьютера ---- ### Параметры app.run() **1. Debug mode**: ```python=1 app.run(debug=True) ``` > - Cервер перезагружается сам при изменении кода > - Позволяет работать с отладчиком > - Не забыть отключить при развертывании сервиса **2. Cделать сервер публично доступным** ```python=1 app.run(host='0.0.0.0') ``` По умолчанию - доступ local ---- ### Шаблоны Шаблон — файл с HTML-кодом и элементами разметки, которые позволяют выводить динамический контент. Функция render_template() вызывает механизм шаблонов Jinja2, который поставляется в комплекте с Flask. ``` python from flask import render_template ``` Шаблоны хранятся в директории /templates ---- Пример шаблона (/templates/index.html): ``` HTML <html> <body> <h1>Prediction: {{ pred }}</h1> </body> </html> ``` Пример кода, которые преобразует шаблон в HTML страницу (рендеринг): ```pyhon from flask import Flask, request, render_template app = Flask(__name__) #some code @app.route('/') def index(): return render_template('index.html', pred=model.prediction) ``` --- ### Flask API **Flask-RESTX** - это расширение для Flask, которое добавляет поддержку для быстрой разработки REST API. Документация: https://flask-restx.readthedocs.io/en/latest/index.html Аналоги: *flask-restplus*, *flask-restful* ---- Простой пример приложения, реализующий API на Flask: ```python=3 from flask import Flask from flask_restx import Api, Resource, fields app = Flask(__name__) api = Api(app) passwords = [] a_password = api.model('Resource', {'password': fields.String}) @api.route('/password') class Prediction(Resource): def get(self): return passwords @api.expect(a_password) def post(self): passwords.append(api.payload) return {'Result': 'pass added'}, 201 ``` ---- Flask-RESTX предоставляет набор инструментов для генерации документации с использованием Swagger. Документация **Swagger API** создается автоматически и доступна по корневому URL API: ![](https://i.imgur.com/RCr0bUH.png =800x) <!-- ### Blueprint * Средство выделения функциональности. * Позволяет переносить как отдельный блок в другие проекты. --> --- ### Deploy [Пошаговое руководство как развернуть Flask приложение на Heroku](https://devcenter.heroku.com/articles/getting-started-with-python) На 4-й лекции более подробно будет разобран вопрос развертывания. Также будет полезно закрепить базовые представления о Git. <!-- https://towardsdatascience.com/creating-restful-apis-using-flask-and-python-655bad51b24 --> --- ## Django ![](https://i.imgur.com/exGf2vi.png =150x) - Что это? - еще один популярный фреймворк на python для разработки веб приложения или API. Особенности: * Встроенная Django Admin * Встроенная защита от наиболее распространенных уязвимостей и атак, в частности: SQL-инъекции,CSRF,XSS, кликджекинг, и т.д. * Поддержка ORM Django - хороший выбор для быстрой разработки масштабируемого приложения. Но не лучший выбор для микросервисов, простого API-приложения без фронтенда и баз данных. <!--- ### Установка ```shell=1 pip install django ``` (используя виртуальное окружение) Переходим в каталог проекта и создаем проект: ``` shell=1 cd my_django_app django-admin startproject my_site . ``` Последняя команда создаст структуру django проекта ### Тестовый запуск приложения ``` shell=1 cd my_site python manage.py runserver ``` Получим вывод: ``` Django version 3.0, using settings 'mysite.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. ``` Запустили Web-сервер для разработки Django! --> --- ## FastAPI **Преимущества:** - встроенная документация API - асинхронность - валидация (pydantic) - быстродействие Установка: ```shell=1 pip install uvicorn fastapi pydantic ``` Интерактивная документация: http://127.0.0.1:8000/docs [Чуть подробнее о FastAPI на хабре](https://habr.com/ru/post/478620/) --- ## Streamlit - Что это? Opensource Python фреймворк для быстрой разработки дашборда в проектах с машинным обучением, не требующий знания frоntend (HTML, CSS и JavaScript) ### Установка ```shell=1 pip install streamlit ``` ### Особенности 1. Виджеты * checkboxes * selectBox * slider * multiSelect (tags) 2. Визуализация * matplotlib * сomponent for rendering Folium maps. ---- <iframe width="100%" height="500" src="https://share.streamlit.io/streamlit/demo-self-driving" frameborder="0"></iframe> --- # UI - Что это? User Interface, пользовательский интерфейс - Зачем? - помочь пользователю, организовав комфортное и, по возможности, интуитивно понятное взаимодействие с сайтом. Включает перечень оформленных графических элементов (кнопок, чекбоксов, селекторов и т.д.) --- ![](https://i.imgur.com/4rUOWCq.png) --- - **HTML** - язык гипертекстовой разметки, определяет содержание и структуру веб-контента [Справочник HTML](https://webref.ru/HTML) - **CSS** - язык иерархических правил, используемый для представления внешнего вида страницы [Справочник CSS](https://webref.ru/css) --- **Bootstrap** Фреймворк, позволяющий быстро создавать адаптивный сайт. Включает набор инструментов для создания сайтов и веб-приложений. Содержит HTML и CSS-шаблоны оформления для типографики, веб-форм, кнопок и прочих компонентов веб-интерфейса https://getbootstrap.com/docs/5.0/getting-started/introduction/ [Описание на русском](https://bootstrap-4.ru/) ---- Базовый шаблон, подключающий bootstrap: ``` html=1 <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous"> <title>Hello, world!</title> </head> <body> <h1>Hello, world!</h1> </body> </html> ``` --- <!-- ## Полезные ссылки Поиграть с игрушечным api: https://jsonplaceholder.typicode.com/ --> --- # Семинар 1. Пробуем работу с **curl** на примере сайта https://reqres.in/: - **get** запрос ```curl curl https://reqres.in/api/users/2 curl https://reqres.in/api/users/2 -i curl https://reqres.in/api/users/2 -I ``` отправляем вывод в файл: ```curl curl -o test_curl.txt https://reqres.in/api/users/2 ``` - **post** запрос ```curl curl -X POST https://reqres.in/api/users -d "name=morpheus&job=datascientist" -i ``` используя json: ```curl curl -d '{"name": "Ivan", "job: "data scientist"}' -H "Accept:application/json" -X POST https://reqres.in/api/users -i ``` --- - **delete** запрос ```curl curl -X DELETE https://reqres.in/api/users/1 -i ``` получаем код 204 и пустое тело --- 2. **Flask** - Изучаем файл [app.py](https://gitlab.com/production-ml/password_app/-/blob/master/app.py) - И шаблон [index.html](https://gitlab.com/production-ml/password_app/-/blob/master/templates/index.html) 3. **Flask API** - Ветка с игрушечным примером, как добавить API в проект: https://gitlab.com/production-ml/password_app/-/blob/test_api/app.py - Запустить приложение и посмотреть работу **Swagger** Добавить запись с помощью curl: ```curl curl -X POST "http://0.0.0.0:5000/password" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"password\": \"qwerty\"}" ``` Посмотреть консоль, где запущено приложение. Должно быть вида: ``` 127.0.0.1 - - [16/Mar/2021 16:57:43] "GET /swagger.json HTTP/1.1" 200 - 127.0.0.1 - - [16/Mar/2021 16:59:31] "POST /password HTTP/1.1" 201 - 127.0.0.1 - - [16/Mar/2021 17:00:31] "POST /password HTTP/1.1" 400 - ``` 4. **Streamlit** - Пример сервиса в отдельной ветке: https://gitlab.com/production-ml/password_app/-/blob/streamlit_try/app.py - Поднимаем сервис локально: ``` streamlit run app.py ``` ![](https://i.imgur.com/aGCMar3.png =400x) <!-- ## Небольшой блиц: (*Как идея) - основные опера --> <!-- https://rapidapi.com/community/api/open-weather-map?endpoint=apiendpoint_f719676c-072b-4a2d-ad2e-78f8375ea9c8 ## RapidAPI После развертывания на сервере (например, Heroku) дает возможность опубликовать ваш собственный API Также предоставляет маркетплейс с более чем 10 000 API: ![](https://i.imgur.com/W1d8anM.png) :::info :pushpin: [Каталог Machine Learning RapidAPI](https://rapidapi.com/category/Machine%20Learning) ::: --> --- # Home work 1. Если вы использовали Jupyter для соревнования, перенести проект в PyCharm / VSCode 2. Подготовить пакетное окружение Pipenv и установить в него необходимые пакеты. (Желательно, сразу разделяя на зависимости, необходимые только для разработки, от зависимостей, необходимых для фактической работы базового кода с помощью аргумента --dev) 4. Используя классы, подготовить методы для предсказания модели (predict) и ее переобучения (fit). 5. С помощью Flask API реализовать на локальной машине возможность получить результат предсказания модели в формате json. 6. *Опционально добавить графический веб-интерфейс (используя Flask)
{"metaMigratedAt":"2023-06-15T18:12:50.926Z","metaMigratedFrom":"YAML","title":"Web сервисы, фреймворки, API","breaks":false,"slideOptions":"{\"theme\":\"white\",\"transition\":\"slide\"}","contributors":"[{\"id\":\"85cfc388-1709-48a7-b624-c9d38aadb9ee\",\"add\":37936,\"del\":19741},{\"id\":\"e0bc91de-98f7-46f8-a3a9-852912833a93\",\"add\":463,\"del\":125}]"}
    550 views