Как да структурирате уеб услуга Flask-RESTPlus за изграждане на продукция

Кредитно изображение - frsjobs.co.uk

В това ръководство ще ви покажа стъпка по стъпка подход за структуриране на уеб приложение Flask RESTPlus за тестване, разработка и производствена среда. Ще използвам базирана на Linux операционна система (Ubuntu), но повечето от стъпките могат да бъдат репликирани в Windows и Mac.

Преди да продължите с това ръководство, трябва да имате основно разбиране на езика за програмиране на Python и микро рамката Flask. Ако не сте запознати с тези, препоръчвам да разгледате уводна статия - Как да използвате Python и Flask за изграждане на уеб приложение.

Как е структурирано това ръководство

Това ръководство е разделено на следните части:

  • Характеристика
  • Какво е Flask-RESTPlus?
  • Настройка и инсталация
  • Настройка и организация на проекта
  • Настройки за конфигурация
  • Копче за скрипт
  • Модели и миграция на бази данни
  • Тестване
  • Конфигурация
  • Потребителски операции
  • Сигурност и удостоверяване
  • Защита на маршрута и разрешение
  • Допълнителни съвети
  • Удължаване на приложението и заключение

Характеристика

Ще използваме следните функции и разширения в рамките на нашия проект.

  • Flask-Bcrypt: Разширение Flask, което предоставя помощни програми за хеширане на bcrypt за вашето приложение.
  • Flask-Migrate: Разширение, което обработва миграцията на база данни на SQLAlchemy за Flask приложения, използващи Alembic. Операциите с база данни се предоставят чрез интерфейса на командния ред Flask или чрез разширението Flask-Script.
  • Flask-SQLAlchemy: Разширение за Flask, което добавя поддръжка за SQLAlchemy към вашето приложение.
  • PyJWT: Библиотека на Python, която ви позволява да кодирате и декодирате JSON Web Tokens (JWT). JWT е отворен, отраслов стандарт (RFC 7519) за надеждно представяне на претенции между две страни.
  • Flask-Script: Разширение, което осигурява поддръжка за писане на външни скриптове във Flask и други задачи от командния ред, които принадлежат извън самото уеб приложение.
  • Пространства от имена (чертежи)
  • Flask-restplus
  • UnitTest

Какво е Flask-RESTPlus?

Flask-RESTPlus е разширение за Flask, което добавя поддръжка за бързо изграждане на REST API. Flask-RESTPlus насърчава най-добрите практики с минимална настройка. Той осигурява съгласувана колекция от декоратори и инструменти, за да опише вашия API и да изложи документацията си правилно (използвайки Swagger).

Настройка и инсталация

Проверете дали имате инсталиран pip, като въведете командата pip --version в терминала, след което натиснете Enter.

пип --версия

Ако терминалът отговори с номера на версията, това означава, че е инсталиран pip, така че преминете към следващата стъпка, в противен случай инсталирайте pip или използвайки Linux мениджъра на пакети, изпълнете командата по-долу на терминала и натиснете Enter. Изберете или Python 2.x ИЛИ 3.x версия.

  • Python 2.x
sudo apt-get install python-pip
  • Python 3.x
sudo apt-get install python3-pip

Настройте обвивка за виртуална среда и виртуална среда (имате нужда само от едно от тях, в зависимост от версията, инсталирана по-горе):

sudo pip инсталирате virtualenv
sudo pip3 инсталирате virtualenvwrapper

Следвайте тази връзка за пълна настройка на обвивка за виртуална среда.

Създайте нова среда и я активирайте, като изпълните следната команда на терминала:

mkproject name_of_your_project

Настройка и организация на проекта

Ще използвам функционална структура, за да организирам файловете на проекта според това, което правят. Във функционална структура шаблоните са групирани в една директория, статични файлове в друга и изгледи в трета.

В директорията на проекта създайте нов пакет, наречен приложение. Вътре в приложението създайте два основни пакета и тествайте. Структурата на вашата директория трябва да изглежда подобна на тази по-долу.

,
├── ап
│ ├── __init__.py
│ ├── основен
│ │ └── __init__.py
│ └── тест
│ └── __init__.py
└── изисквания.txt

Ще използваме функционална структура, за да модулираме нашето приложение.
Вътре в основния пакет създайте още три пакета, а именно: контролер, сервиз и модел. Моделният пакет ще съдържа всички наши модели бази данни, докато сервизният пакет ще съдържа цялата бизнес логика на нашето приложение и накрая пакетът контролер ще съдържа всички крайни точки на нашето приложение. Дървесната структура трябва да изглежда по следния начин:

,
├── ап
│ ├── __init__.py
│ ├── основен
│ │ ├── контролер
│ │ │ └── __init__.py
│ │ ├── __init__.py
│ │ ├── модел
│ │ │ └── __init__.py
│ │ └── обслужване
│ │ └── __init__.py
│ └── тест
│ └── __init__.py
└── изисквания.txt

Сега нека инсталирате необходимите пакети. Уверете се, че виртуалната среда, която сте създали, е активирана и изпълнете следните команди на терминала:

pip инсталирате колба-bcrypt
pip инсталирате колба-restplus
пип инсталиране Flask-Migrate
pip инсталирате pyjwt
пип инсталиране Flask-Script
pip инсталирате flask_testing

Създайте или актуализирайте файла файл.txt, като стартирате командата:

pip замразяване> изисквания.txt

Генерираният файл request.txt трябва да изглежда подобно на този по-долу:

алембик == 0.9.8
aniso8601 == 3.0.0
bcrypt == 3.1.4
cffi == 1.11.5
кликнете == 6.7
Flask == 0.12.2
Flask-Bcrypt == 0.7.1
Flask-Мигриране == 2.1.1
колба-restplus == 0.10.1
Flask-Script == 2.0.6
Flask-SQLAlchemy == 2.3.2
Flask-Тестване == 0.7.1
itsdangerous == 0.24
Jinja2 == 2.10
jsonschema == 2.6.0
Мако == 1.0.7
MarkupSafe == 1.0
pycparser == 2.18
PyJWT == 1.6.0
питон-dateutil == 2.7.0
питон-редактор == 1.0.3
pytz == 2018.3
шест == 1.11.0
SQLAlchemy == 1.2.5
Werkzeug == 0.14.1

Настройки за конфигурация

В основния пакет създайте файл, наречен config.py със следното съдържание:

Конфигурационният файл съдържа три класа за настройка на средата, които включват тестване, разработка и производство.

Ще използваме фабричния модел на приложението за създаване на нашия Flask обект. Този модел е най-полезен за създаване на множество екземпляри от нашето приложение с различни настройки. Това улеснява лекотата, с която превключваме между нашата тестова, разработваща и производствена среда, като извикваме функцията create_app с необходимия параметър.

Във файла __init__.py вътре в основния пакет въведете следните редове от код:

Копче за скрипт

Сега нека създадем нашата точка за въвеждане на приложение. В основната директория на проекта създайте файл, наречен Manag.py със следното съдържание:

Горният код в Manag.py прави следното:

  • ред 4 и 5 импортират съответно модулите за мигриране и мениджър (скоро ще използваме командата migrate).
  • ред 9 извиква функцията create_app, която първоначално създадохме, за да създадем екземпляра на приложението с необходимия параметър от променливата на околната среда, който може да бъде един от следните - dev, prod, test. Ако нито една не е зададена в променливата на средата, се използва стандартният dev.
  • ред 13 и 15 създава екземпляр на мениджъра и мигрира класове, като предава екземпляра на приложението на съответните им конструктори.
  • В ред 17 предаваме db и MigrateCommandin вещества към интерфейса add_command на мениджъра, за да изложим всички команди за миграция на базата данни чрез Flask-Script.
  • ред 20 и 25 маркира двете функции като изпълними от командния ред.
Flask-Migrate излага два класа, Migrate и MigrateCommand. Migrateclass съдържа цялата функционалност на разширението. Класът MigrateCommand се използва само когато е желателно да се разкрият команди за миграция на базата данни чрез разширението Flask-Script.

В този момент можем да тестваме приложението, като изпълним командата по-долу в основната директория на проекта.

python manage.py run

Ако всичко е наред, трябва да видите нещо подобно:

Модели и миграция на бази данни

Сега нека създадем нашите модели Ще използваме db инстанцията на sqlalchemy, за да създадем нашите модели.

Инстанцията db съдържа всички функции и помощници както от sqlalchemy, така и от sqlalchemy.orm и предоставя клас, наречен Model, който е декларативна база, която може да се използва за деклариране на модели.

В пакета с модели създайте файл, наречен user.py със следното съдържание:

Горният код в user.py прави следното:

  • ред 3: Потребителският клас наследява от db.Model клас, който декларира класа като модел за sqlalchemy.
  • ред 7 до 13 създава необходимите колони за потребителската таблица.
  • ред 21 е сетер за полето password_hash и той използва flask-bcrypt за генериране на хеш с предоставената парола.
  • ред 24 сравнява дадена парола с вече запазения password_hash.

Сега, за да генерираме таблицата на базата данни от потребителския модел, който току-що създадохме, ще използваме migrateCommand чрез интерфейса на мениджъра. За да разпознаем мениджъра си, ще трябва да импортираме модела theuser, като добавим код по-долу, за да управлявате файл.py:

...
от потребителя за импортиране на app.main.model
...

Сега можем да пристъпим към извършване на миграцията, като изпълним следните команди в основната директория на проекта:

  1. Инициирайте папка за миграция, използвайки команда init за alembic, за да извършите миграциите.
python Manag.py db init

2. Създайте сценарий за миграция от откритите промени в модела с помощта на командата migrate. Това все още не засяга базата данни.

python Manag.py db migrate - съобщение „първоначална миграция на база данни“

3. Приложете скрипта за миграция към базата данни, като използвате командата за надстройка

надстройка на python manag.py db

Ако всичко работи успешно, трябва да имате нова база данни sqlLite
 файл flashk_boilerplate_main.db, генериран в основния пакет.

Всеки път, когато моделът на базата данни се променя, повтаряйте командите за мигриране и надстройка

Тестване

Конфигурация

За да сте сигурни, че настройката за нашата конфигурация на средата работи, нека напишем няколко теста за нея.

Създайте файл, наречен test_config.py в тестовия пакет със съдържанието по-долу:

Изпълнете теста с помощта на командата по-долу:

python management.py тест

Трябва да получите следния изход:

Потребителски операции

Сега нека работим върху следните операции, свързани с потребителите:

  • създаване на нов потребител
  • получаване на регистриран потребител с неговия public_id
  • получаване на всички регистрирани потребители.

Клас за обслужване на потребители: Този клас обработва цялата логика, свързана с потребителския модел.
В сервизния пакет създайте нов файл user_service.py със следното съдържание:

Горният код в user_service.py прави следното:

  • ред 8 до 29 създава нов потребител, като първо проверява дали потребителят вече съществува; той връща успешен отговор_объект, ако потребителят не съществува друго, той връща код за грешка 409 и обект отговор на неуспех.
  • 33 и 37 връщат списък на всички регистрирани потребители и потребителски обект, като предоставят съответно public_id.
  • ред 40 до 42 извършва промени в базата данни.
Няма нужда да използвате jsonify за форматиране на обект в JSON, Flask-restplus го прави автоматично

В основния пакет създайте нов пакет, наречен util. Този пакет ще съдържа всички необходими помощни програми, от които може да се нуждаем в нашето приложение.

В пакета на util създайте нов файл dto.py. Както подсказва името, обектът за пренос на данни (DTO) ще отговаря за пренасянето на данни между процесите. В нашия собствен случай той ще бъде използван за прехвърляне на данни за нашите API обаждания. Ще разберем това по-добре, докато продължим.

Горният код в dto.py прави следното:

  • ред 5 създава ново пространство за имена за свързани с потребителите операции. Flask-RESTPlus предоставя начин за използване на почти същия модел като Blueprint. Основната идея е да разделите приложението си на пространства от имена за многократна употреба. Модулът в пространството на имена ще съдържа модели и декларация за ресурси.
  • ред 6 създава нов потребител dto чрез интерфейса на модела, осигурен от пространството на имена api в ред 5.

Потребителски контролер: Класът на потребителския контролер обработва всички входящи HTTP заявки, свързани с потребителя.

Под пакета на контролера създайте нов файл, наречен user_controller.py със следното съдържание:

ред 1 до 8 импортира всички необходими ресурси за контролера на потребителя.
Дефинирахме два конкретни класа в нашия потребителски контролер, които са userList и user. Тези два класа разширяват абстрактния ресурс на колба-restplus.

Конкретните ресурси трябва да се простират от този клас и да излагат методи за всеки поддържан HTTP метод. Ако ресурс бъде извикан с неподдържан HTTP метод, API ще върне отговор със състояние 405 Методът не е разрешен. В противен случай се извиква подходящият метод и се предават всички аргументи от правилото за URL, използвано при добавяне на ресурса към екземпляр на API.

Пространството с имена на api в ред 7 по-горе осигурява на контролера няколко декоратора, което включва, но не се ограничава до следното:

  • api.route: декоратор за маршрутизиране на ресурси
  • api.marshal_with: Декоратор, определящ полетата, които да се използват за сериализация (Това е мястото, където използваме userDto, което сме създали по-рано)
  • api.marshal_list_with: Декоратор на пряк път за marhal_with по-горе с as_list = True
  • api.doc: Декоратор за добавяне на документация на api към украсения обект
  • api.response: декоратор за уточняване на един от очакваните отговори
  • api.expect: Декоратор за уточняване на очаквания модел на въвеждане (ние все още използваме userDto за очаквания вход)
  • api.param: Декоратор за уточняване на един от очакваните параметри

Вече сме дефинирали нашето пространство с имена с потребителския контролер. Сега е време да го добавите към точката за въвеждане на приложение.

Във файла __init__.py на пакета за приложения въведете следното:

Горният код в blueprint.py прави следното:

  • В ред 8 създаваме екземпляр на план, като предаваме име и име на име. API е основната входна точка за ресурсите на приложението и затова трябва да бъде инициализиран с чертежа в ред 10.
  • В ред 16 ние добавяме потребителското пространство user_ns към списъка с пространства от имена в екземпляра на API.

Сега дефинирахме нашия план. Време е да го регистрирате в нашето приложение Flask.
Актуализирайте management.py, като импортирате план и го регистрирате в екземпляра на приложението Flask.

от план за импортиране на приложение
...
app = create_app (os.getenv ('BOILERPLATE_ENV') или 'dev')
app.register_blueprint (план)
app.app_context (). натиснете ()
...

Вече можем да тестваме нашето приложение, за да видим, че всичко работи добре.

python manage.py run

Сега отворете URL адреса http://127.0.0.1.1000000 във вашия браузър. Трябва да видите документацията за фалшифициране.

Нека да тестваме създаването на нова потребителска крайна точка, използвайки функционалността за тестване на замах.

Трябва да получите следния отговор

Сигурност и удостоверяване

Нека създадем моделен черен списък, Създаден за съхранение на маркировки в черен списък. В пакета с модели създайте файл blacklist.py със следното съдържание

Да не забравяме да мигрираме промените, за да влязат в сила върху нашата база данни.
Импортирайте класа на черния списък в Manag.py.

от черен списък за импортиране на app.main.model

Изпълнете командите за мигриране и надстройка

python Manag.py db migrate - съобщение „добавете таблица с черен списък“
надстройка на python manag.py db

След това създайте blacklist_service.py в сервизния пакет със следното съдържание за черен списък на означение

Актуализирайте потребителския модел с два статични метода за кодиране и декодиране на маркери. Добавете следния внос:

време за импортиране
import jwt
от app.main.model.blacklist import BlacklistToken
ключ за импортиране ..config
  • Encoding
  • Декодиране: Токенът в черен списък, токът с изтекъл срок и невалидният маркер се вземат предвид при декодиране на маркера за удостоверяване.

Сега нека напишем тест за потребителския модел, за да гарантираме, че функциите ни за кодиране и декодиране работят правилно.

В тестовия пакет създайте base.py файл със следното съдържание

BaseTestCase създава нашата тестова среда, готова преди и след всеки тестов случай, който го разширява.

Създайте test_user_medol.py със следните тестови случаи:

Изпълнете теста с python Manag.py тест. Всички тестове трябва да преминат.

Нека създадем крайните точки за удостоверяване за влизане и излизане.

  • Първо се нуждаем от dto за полезния товар за вход. Ще използваме auth dto за пояснението @expect в крайната точка за вход. Добавете кода по-долу към dto.py
  • След това създаваме помощен клас за удостоверяване за обработка на всички операции, свързани с удостоверяването. Този auth_helper.py ще бъде в пакета за услуги и ще съдържа два статични метода, които са login_user и logout_user
Когато потребителят е излязъл, токенът на потребителя е в черен списък, т.е. потребителят не може да влезе отново със същия този маркер.
  • Нека сега създадем крайни точки за операции за влизане и излизане.
    В пакета на контролера създайте auth_controller.py със следното съдържание:
  • Към този момент единственото, което остава е да регистрирате пространството от имена auti api с приложението Blueprint

Актуализирайте __init__.py файла на пакета за приложения със следното

# app / __ init__.py
от flask_restplus import Api
от импортна програма за импортиране в колба

от .main.controller.user_controller импортиране api като user_ns
от .main.controller.auth_controller импортиране api като auth_ns

blueprint = Blueprint ('api', __name__)

api = Api (план,
          title = 'FLASK RESTPLUS API BOILER-PLATE С JWT',
          версия = "1.0",
          description = 'котло за уеб-услуга с колба restplus'
          )

api.add_namespace (user_ns, path = '/ user')
api.add_namespace (auth_ns)

Стартирайте приложението с изпълнение на python Manag.py и отворете URL адреса http://127.0.0.1.1000000 във вашия браузър.

Документацията на swagger сега трябва да отразява новосъздаденото пространство за имена на auth с крайните точки за влизане и излизане.

Преди да напишем някои тестове, за да гарантираме, че автентификацията ни работи, както се очаква, нека модифицираме нашата крайна точка за регистрация, за да влезете автоматично, след като регистрацията е успешна.

Добавете метода create_token по-долу към user_service.py

Методът gene_token генерира маркер за удостоверяване чрез кодиране на потребителския идентификатор. Този знак се връща като отговор.

След това заменете блока за връщане в метода save_new_user по-долу

response_object = {
    'статус': 'успех',
    'message': 'Регистриран успешно.'
}
връщане отговор_объект, 201

с

върнете gene_token (new_user)

Сега е време да тествате функциите за влизане и излизане. Създайте нов тестов файл test_auth.py в тестовия пакет със следното съдържание

Посетете github repo за по-изчерпателни тестови случаи.

Защита на маршрута и разрешение

Досега успешно създадохме нашите крайни точки, внедрихме функционалности за влизане и излизане, но нашите крайни точки остават незащитени.

Трябва ни начин да определим правила, които определят коя от крайните ни точки е отворена или изисква удостоверяване или дори администраторска привилегия.

Можем да постигнем това, като създадем персонализирани декоратори за нашите крайни точки.

Преди да можем да защитим или разрешим някоя от нашите крайни точки, трябва да знаем текущо влезлия потребител. Можем да направим това, като издърпаме маркера за оторизация от заглавката на текущата заявка, използвайки заявката на библиотеката с колби. След това декодираме потребителските детайли от маркера за оторизация.

В класа Auth на файла auth_helper.py добавете следния статичен метод

Сега, когато можем да извлечем влезлия потребител от заявката, нека да продължим и да създадем декораторите.

Създайте файл decorator.py в пакета util със следното съдържание

За повече информация относно декораторите и как да ги създадете, разгледайте този линк.

Сега, след като създадохме декораторите token_required и admin_token_required за валиден токен и съответно за администраторски токен, всичко, което ни остава, е да анотираме крайните точки, които искаме да защитим с безплатния декодер на codecode.

Допълнителни съвети

В момента за изпълнение на някои задачи в нашето приложение, от нас се изисква да стартираме различни команди за стартиране на приложението, провеждане на тестове, инсталиране на зависимости и т.н. Можем да автоматизираме тези процеси, като подредим всички команди в един файл с Makefile.

В основната директория на приложението създайте Makefile без разширение на файла. Файлът трябва да съдържа следното:

.PHONY: изчистените системни пакети python-пакети инсталират тестове изпълняват всички

почистване:
   намирам . -тип f -name '* .pyc' -изтриване
   намирам . -тип f -name '* .log' -delete

системни опаковки:
   sudo apt инсталирате python-pip -y

Питон пакети:
   pip install -r изисквания.txt

инсталирайте: системни пакети python-пакети

тестове:
   python management.py тест

изпълнете:
   python manage.py run

всички: тестовете за чиста инсталация се изпълняват

Ето опциите на make файла.

  1. make install: инсталира както системни пакети, така и python-пакети
  2. почисти: изчисти приложението
  3. направи тестове: изпълнява всички тестове
  4. make run: стартира приложението
  5. направи всичко: извършва почистване, инсталация, стартира тестове и стартира приложението.

Удължаване на приложението и заключение

Доста лесно е да копирате текущата структура на приложението и да го разширите, за да добавите повече функционалности / крайни точки към приложението. Просто прегледайте всеки от предишните маршрути, които са били изпълнени.

Чувствайте се свободни да оставите коментар имате ли някакъв въпрос, наблюдения или препоръки. Освен това, ако тази публикация е била полезна за вас, кликнете върху иконата за хлопане, така че другите ще виждат това тук и ще се възползват.

Посетете хранилището на github за целия проект.

Благодаря за четенето и късмет!