Файл: Методические указания по выполнению лабораторных работ для студентов, обучающихся с применением.pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 05.12.2023
Просмотров: 132
Скачиваний: 3
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
"sitepart"
,
__name__
, template_folder
=
'templates'
,
static_folder
=
'static'
)
# Возвращает цветовую палитру по имени палитры (rgb, cmyk ...)
@sitepart.route
(
'/colors/
/'
)
def colors
(
palette
)
:
"""Example endpoint returning a list of colors by palette
This is using docstrings for specifications.
--- parameters:
- name: palette in: path type: string enum: ['all', 'rgb', 'cmyk']
required: true default: all definitions:
Palette:
type: object properties:
,
__name__
, template_folder
=
'templates'
,
static_folder
=
'static'
)
# Возвращает цветовую палитру по имени палитры (rgb, cmyk ...)
@sitepart.route
(
'/colors/
/'
)
def colors
(
palette
)
:
"""Example endpoint returning a list of colors by palette
This is using docstrings for specifications.
--- parameters:
- name: palette in: path type: string enum: ['all', 'rgb', 'cmyk']
required: true default: all definitions:
Palette:
type: object properties:
102 palette_name:
type: array items:
$ref: '#/definitions/Color'
Color:
type: string responses:
200:
description: A list of colors (may be filtered by palette)
schema:
$ref: '#/definitions/Palette'
examples:
rgb: ['red', 'green', 'blue']
"""
# содержимое цветов палитр all_colors
=
{
'cmyk'
:
[
'cian'
,
'magenta'
,
'yellow'
,
'black'
],
'rgb'
:
[
'red'
,
'green'
,
'blue'
]
}
# что возвратить, если URL all if palette
==
'all'
:
result
= all_colors else:
# возврат в зависимости от имени палитры result
=
{
palette
: all_colors get
(
palette
)}
# преобразуем словарь в json строку и возвращаем ее return jsonify
(
result
)
Здесь используется код с официального репозитория Flasgger, как видим, схема использует тип Palette, являющийся объектом, который содержит массив цветов, каждый при этом цвет является строкой. Соответственно, для нашего сайта доступ к этой части API будет реализован через URL http://127.0.0.1:5000/sitepart/colors/all/ или http://127.0.0.1:5000/sitepart/colors/rgb/ и т. д. При этом вы получите, например, такой результат (рис. 3.1) или в форма- те json {
103
"cmyk": [
"cian",
"magenta",
"yellow",
"black"
],
"rgb": [
"red",
"green",
"blue"
]
}
Рис. 3.1 – Результат запроса по URL к нашему API
Результат запроса apidocs отображен на рисунке 3.2.
Рис. 3.2 – Пример отображения информации об API
104
3.2 Использование библиотеки flask_restplus
для документирования веб-сервиса
Далее рассмотрим другую библиотеку, она несколько удобнее для веде- ния документации. Эта библиотека flask_restplus, кроме того она позволяет со- здавать отдельные части API, также как и Blueprint. То есть вы, например, мо- жете создавать API с документацией, используя flask_restplus, а визуальную часть сайта реализовывать, используя Blueprint, создавая интерфейс пользова- теля и т. д. При этом для описания отдельных частей API используются неймспейсы.
Папки и файлы проекта. part part/static part/templates part/part.py part/parttmpl.py main.py
Содержимое файлов. part.py
Более удобно в этом плане использовать модуль flask_restplus, создадим еще одну среду.
(proj2)pip install flask_restplus=0.13.0
(proj2)pip install Werkzeug==0.16.1
Структура папок здесь будет такой: part part/static part/templates part/part.py part/parttmpl.py
105 main.py main.py from flask import
Flask
,
Blueprint from flask_restplus import
Api
,
Resource app
=
Flask
(
__name__
)
api
=
Api
(
app
= app
)
# описание главного блока нашего API http://127.0.0.1:5000/main/. name_space
= api namespace
(
'main'
, description
=
'Main APIs'
)
@name_space.route
(
"/"
)
class
MainClass
(
Resource
)
:
def get
(
self
)
:
return
{
"status"
:
"Got new data"
}
def post
(
self
)
:
return
{
"status"
:
"Posted new data"
}
# подключение API из другого файла from part part import api as partns1
api add_namespace
(
partns1
)
from part.parttmpl import api as partns2 from part.parttmpl import templ as templ api.add_namespace(partns2) app.register_blueprint(templ,url_prefix='/templ') app.run(debug=True)
Далее описан файл, содержащий отдельную часть API по другому URL http://127.0.0.1:5000/part/
и http://127.0.0.1:5000/part/id
, под id здесь понимается любой передаваемый идентификатор в запросе URL. part.py from flask_restplus import
Namespace
,
Resource
, fields api
=
Namespace
(
'part'
, description
=
'some information'
)
# описание возвращаемых полей info
= api model
(
'part'
, {
106
'id'
: fields
String
(
required
=True
, description
=
'The identifier'
),
'name'
: fields
String
(
required
=True
, description
=
'The name'
),
})
INFO
=
[
{
'id'
:
'1111'
,
'name'
:
'Alex'
},
]
@api.route
(
'/'
)
class
InfoList
(
Resource
)
:
@api.marshal_list_with
(
info
)
def get
(
self
)
:
'''List all
/ это описание появится в браузере на экране напротив get'''
return
INFO
# URL вида http://127.0.0.1:5000/part/1111
http://127.0.0.1:5000/part/
2.
@api.route
(
'/
)
@api.param
(
'id'
,
'The identifier'
)
@api.response
(
404
,
'id not found'
)
class
InfoId
(
Resource
)
:
@api.doc
(
params={'id': 'An ID'}
)
# описание id в документации по адресу 127.0.0.1
@api.marshal_with
(
info
)
def get
(
self
, id
)
:
for idi in
INFO
:
if idi
[
'id'
]
== id
:
return idi else:
return
{
'id'
: id
,
'name'
:
'your name'
},
api abort
(
404
)
Здесь можно указать ограничение на id следующим образом:
@api.route('/
Таким образом, id должен быть целым, теперь, если вы запустите тот же проект, но с данной заменой, на id, взятую как строка с нецелым значением, мы получим возврат ошибки.
107
Декоратор api.doc позволяет документировать ваш API дополнительно, например, напротив параметра id будет выводиться дополнительная информа- ция An id.
Можно для конкретного метода уточнить описания ответов. Например, если добавить responses методу get
@api.doc(params={'id': 'An ID'}, responses={404: 'ID Not Found'}), то вме- сто 'id not found', будет написано 'ID Not Found'.
Также мы видим применение декоратора маршалинга к запросу get, фак- тически это то же самое, что return marshal(db_get_todo(), model), 200, то есть применение маршалинга к данным, возвращенным из базы данных в соответ- ствии с моделью данных. В нашем случае, например, return marshal(
{
'id'
: id
,
'name'
:
'your name'
}, info), 200 или return marshal(idi
, info), 200.
В Python термин «маршалинг» схож с термином «сериализация». Как ви- дите, здесь объект «словарь» сериализуется в строку, передаваемую пользова- телю. Под маршалингом в компьютерных сетях понимается преобразование данных в формат, пригодный для передачи по сети, и затем преобразование в исходный формат. В общем случае маршалинг – это еще и запись состояния объекта так, чтобы можно было получить копию исходного объекта, путем ав- томатической загрузки определений класса объекта (фактически при марша- линге передаются еще и описания объекта и его код или расположение кода), в целом мы видим, что и здесь определения класса объекта загружаются авто- матически. Маршалинг реализует представление объекта для получателя. При сериализации просто происходит преобразование объекта в битовую строку и обратно (в некоторых случаях сериализация – это частный случай маршалин- га или способ реализации).
Здесь приводится пример шаблона http://127.0.0.1:5000/templ/. parttmpl.py from flask import
Blueprint from flask_restplus import
Api
108 templ
=
Blueprint
(
'templ'
,
__name__
, template_folder
=
'templates'
,
static_folder
=
'static'
)
api
=
Api
(
templ
)
@templ.route
(
"/"
)
def index
()
:
return
"template"
Опишем передачу, добавление и валидацию данных. Для этого рассмот- рим простой пример работы с массивами. Здесь мы зададим некую модель мас- сива, которая содержит размер массива и сам массив строковых значений. Раз- берите пример, который приведен ниже, можно вставить данный код до app.run.
В данном случае можно провести валидацию данных, передаваемых в теле за- проса post с помощью декоратора expect, данные должны соответствовать опре- делениям модели. Маршалинг, как и ожидается, позволяет преобразовать дан- ные в формат json. from flask_restplus import fields
# определение модели данных массива list_
= api model
(
'list'
, {
'len'
: fields
String
(
required
=True
, description
=
'Size of array'
),
'array'
: fields
List
(
fields
String
,
required
=True
, description
=
'Some array'
),
})
# массив, который хранится в оперативной памяти allarray
=
[
'1'
]
name_space1
= api namespace
(
'list'
, description
=
'list APIs'
)
@name_space1.route
(
"/"
)
class
ListClass
(
Resource
)
:
@name_space1.doc
(
""
)
@name_space1.marshal_with
(
list_
)
def get
(
self
)
:
""""Получение всего хранимого массива"""
return
{
'len'
: str
(
len
(
allarray
)),
'array'
: allarray
}
@name_space1.doc
(
""
)
# ожидаем на входе данных в соответствии с моделью list_
@name_space1.expect
(
list_
)
# маршалинг данных в соответствии с list_
@name_space1.marshal_with
(
list_
)
def post
(
self
)
:
"""Создание массива/наше описание функции пост"""
global allarray
# получить переданный массив из тела запроса allarray
= api payload
[
'array'
]
# возвратить новый созданный массив клиенту return
{
'len'
: str
(
len
(
allarray
)),
'array'
: allarray
}
109
# модель данные с двумя параметрами строкового типа minmax
= api model
(
'minmax'
, {
'min'
:
fields
String
,
'max'
:
fields
String
}, required
=True
, description
=
'two
values'
)
# url 127.0.0.1/list/mimmax
@name_space1.route
(
"/minmax"
)
class
MinMaxClass
(
Resource
)
:
@name_space1.doc
(
""
)
# маршалинг данных в соответствии с моделью minmax
@name_space1.marshal_with
(
minmax
)
def get
(
self
)
:
"""Получение максимума и минимума массива"""
global allarray return
{
'min'
: min
(
allarray
),
'max'
: max
(
allarray
)}
api add_namespace
(
name_space1
)
Можно выполнять запросы, используя Swagger. Для этого нажимаем кнопку Try it out.
Данные можно ввести в открывшемся поле (Edit value), например,
{
"len":"3", "array": ["11","5","3"]
} (
рис. 3.3).
Рис. 3.3 – Ввод данных для запроса Post
Далее добавим пример, где данные передаются в запросе GET и в ответ возвращается результат. В данном примере в запросе GET передаются парамет-
110 ры, которые задают размер массива, минимальное и максимальное значение равномерного распределения. from flask_restplus import reqparse from random import random reqp
= reqparse
RequestParser
()
# добавление аргументов, передаваемых запросом GET
# например GET http://127.0.0.1:5000/list/makerand?len=7&minval=1&maxval=12
reqp add_argument
(
'len'
, type
=
int
, required
=False
)
reqp add_argument
(
'minval'
, type
=
float
, required
=False
)
reqp add_argument
(
'maxval'
, type
=
float
, required
=False
)
@name_space1.route
(
"/makerand"
)
class
MakeArrayClass
(
Resource
)
:
@name_space1.doc
(
""
)
# маршалинг данных в соответствии с моделью minmax
@name_space1.expect
(
reqp
)
@name_space1.marshal_with
(
list_
)
def get
(
self
)
:
"""Возвращение массива случайных значений от min до max"""
args
= reqp parse_args
()
array
=
[
random
()
*
(
args
[
'maxval'
]
- args
[
'minval'
])
+
args
[
'minval'
] for i in range
(
args
[
'len'
])]
return
{
'len'
: args
[
'len'
],
'array'
: array
}
Таким образом, мы в итоге получили функцию получения массива слу- чайных значений. Пример достаточно простой, но он демонстрирует возможно- сти фреймворка по валидации данных API и документирования. Итоговый набор запросов представлен на рисунке 3.4, очевидно, что можно использовать и запросы put, patch и delete.
Рис. 3.4 – Пример Swagger документации API
111
Более подробное описание библиотеки flask_restplus можно найти по ссылке: https://flask-restplus.readthedocs.io/en/stable/
3.3
Задание на лабораторную работу № 2
Необходимо повторить описанные в главе 3 примеры и создать свой соб- ственный веб-сервис и API, реализующий возврат данных по заданию в соот- ветствии с вариантом, где задана простая предметная область. Необходимо раз- работать простую модель данных, в соответствии с которой будут храниться данные, соответствующие предметной области. Количество полей должно быть более четырех, два-три поля могут быть строкового или другого типа, осталь- ные – числового.
Веб-сервис должен предоставлять возможность сортировки по всем по- лям записей, выдавать среднее, максимальное и минимальное значение по чис- ловым полям, добавлять, удалять записи и обновлять записи, например, по идентификатору.
Например, для предметной области «Продажа сервизов» можно выделить поля:
«Название сервиза»;
«
Фирма-производитель»;
«
Количество предметов»;
«
Цена сервиза»;
«
Материал».
Предметная область «Школьники, изучающие предметы в школе»:
«
Ф.И.О.»;
«
Название предмета»;
«
Номер четверти»;
«
Оценка»;
«
Год начала учебы»;
«
Возраст» и т. д.