Рубрики
Без рубрики

Колбовые приложения, Докер и систему инвентаризации автомобиля

Создание приложения, состоящего из нескольких приложений для колб, развернутых с помощью Docker-Compose T … Теги с Python, Docker, Minerervices, учебником.

Этот пост адаптирован из readme of Это руководство репо Что я написал с намерением публиковать здесь. При чтении этого руководства вы должны обратиться к исходным коде в репо. Если у вас есть какие-либо предложения или улучшения, пожалуйста, пожалуйста, комментируйте или создайте запрос на тягу на REPO GitHub.

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

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

Контекст

Недавно я работал над большим многокомпонентным приложением, построенным со многими службами Flask Micro и обнаружил трудности на всей территории, где даже более глубокие поиски Google не смогли помочь мне на правильный ответ. В то время я не думал, что написал руководство по этому поводу, поэтому я не принял к сведению большинство этих вопросов, но это руководство надеется охватить все, что я хотел бы, чтобы я мог бы найти более легко.

Стек используется в этом руководстве:

  • Python 3.7
  • Флясные бэкэндуки
  • Sqlite3. с колбой SQL Alchemy
  • Докер
  • Докер-состав
  • Почтальон

Предпосылки:

  • Обработчик среды Python, потому что мы создадим несколько сред. Я использую CONDA, но вы также можете использовать что-то вроде вена или поэзии.
  • Python 3.7+
  • Вам нужно установить Docker, это руководство не будет покрывать этот процесс, потому что Докерская документация очень полный
  • Почтальон – Проверьте здесь
  • Некоторые знания о колбных приложений, SQL SULMS и Docker.

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

Терминология:

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

  • Клиент: Конечный пользователь, который потребляет пользовательский интерфейс в своем браузере
  • API-клиент: все, что потребляет API (внутренний или внешний)
  • Backend: Backend – это любая система, которая обнародовала потребление API. Это может быть простое приложение Flask или Express App или любые другие вещи, которые не обязательно являются серверами HTTP.
  • Применение: Приложение – это набор бэкэндов, которые работают вместе, или она может обратиться к отдельным приложениям в колбе.
  • Frontend: система, которая обрабатывает прямые клиентские взаимодействия, поэтому это охватывает UI (например, WebApp или мобильное приложение).
  • Компонент: бэкэнды и интернаты могут рассматриваться как компоненты. Компоненты автономные и должны быть проверены/тестированы сами по себе.

Что мы сделаем?

То, что мы намереваемся сделать Backend Application, состоящее из нескольких микросервисов. Как правило, можно найти руководства, показывающие кому-то, как сделать любой индивидуальный раздел этого руководства, и, как правило, они используют другой стек, включающий в себя больше бэкэндов на основе JavaScript или используя базы данных, такими как FireStore или Dynamo.

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

Дополнительный шаг станет Backend Gateway API, который является своего рода маршрутизатором и авторитетом клиентских запросов. Это означает, что наше «приложение» будет состоять из двух бэкэндских компонентов, один из которых является инвентарный менеджер, и один из которых является шлюз API. Приложение раскрывает реставральный интерфейс (мы доберемся до этого).

Что такое сценарий?

Выдающаяся технологическая компания разветвлена на самостоятельный автомобильный рынок. В целях сокращения выбросов Компания инвестировала в создание сети самостоятельных автомобилей, грузовых автомобилей и грузовых автомобилей. Их клиенты могут запрашивать автомобиль, чтобы пойти от местоположения A до местоположения B для множества целей. Вы можете запросить поездку, или вы можете вызвать грузовик для транспортировки грузов, среди других целей.

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

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

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

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

Каков объем системы управления инвентарами?

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

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

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

Определение системы?

Перед началом начать, мы должны определить нашу систему в некоторой степени и определить, как мы ожидаем, что пользователь сможет взаимодействовать с ним. Мы делаем это с помощью диаграмм UML и диаграммы последовательности соответственно.

UML:

Мы можем описать нашу систему следующей диаграммой. Это позволяет нам четко визуализировать каждый компонент и соответствующие ссылки между нашими компонентами. UML ничего не говорит о содержании интерфейсов.

Основная диаграмма последовательности:

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

Расширенная диаграмма последовательности:

С точки зрения внутренней разработки может быть полезно увидеть больше информации, которая не должна подвергаться воздействию клиента API, мы можем сделать это со следующей диаграммой:

Чугерс:

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

Наша система является приложением Basic Crud (Create, Read, Update, Delete) с некоторыми дополнительными проверками, поэтому наши приложения Swagger должны быть довольно простыми (возможно, я добавлю это позже).

Разработка:

Мы начнем с разработки заявки на управление запасами, а затем работать наружу к системе шлюза. Если вы работаете, это Agile Team, вы узнаете, что это не тот подход. То, что мы здесь делаем, называется «горизонтальным нарезкой», когда вы будете делать в агильной среде, – это «вертикальная нарезка».

Горизонтальные нарезки – это практика разделения развития в технические слои. Такие как расщепление проекта на Frontend, Backend, слой базы данных. Горизонтальные нарезки требуют, чтобы все ломтики были завершены до того, как клиент может использовать программное обеспечение.

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

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

Так что развитие будет происходит следующим образом:

Anduction Management Flask App -> API Gateway Application -> Комбинированное развертывание

Приложение для управления инвентарями (Invsys):

Начните с создания нового каталога в нашем каталоге проекта, мы назовем это Invsys , короткий для системы инвентаризации. CD в этот каталог, потому что все разработки в этом разделе будут сделаны в Invsys Отказ Вы должны создать новую среду Python для этого компонента, чтобы он мог быть самим собой, содержащийся с отслеживанием собственных зависимостей.

Это приложение представляет собой приложение Flask, которое обнажает API для создания ресурсов (автомобиль, грузовик, грузовик) и создание ассигнований для экземпляров.

Итак, мы создаем файл под названием application.py Что мы будем использовать для создания функции, которая создаст наше приложение. Почему функция создать приложение вместо того, чтобы просто создать приложение на уровне модуля? Ну, если мы хотим динамическую конфигурацию, например, для создания тестового приложения или приложения для производства, то полезно иметь возможность пропускать параметры или конфигурации при создании приложения. Если мы определим приложение на уровне модуля, без функции для его создания сложнее обрабатывать динамические конфигурации.

Приложение для фиктивных колб может выглядеть следующее:

# application.py

from flask import Flask, Response

def create_application() -> Flask:
    app = Flask(__name__)

    @app.route("/", methods=["GET"])
    def dummy():
        return Response("This is InvSys")

    return app

if __name__=="__main__":
    app = create_application()
    app.run(host="127.0.0.1", port=5000, debug=True)

Перед запуском этого вы заметите, что импортируем модуль Flask, поэтому в новой среде Python для Invsys Установите флабу с помощью Установка PIP колбы , иначе вы получите zourseRor, как "ImporteRoror: Нет модуля по имени Flask" Отказ

Если вы запускаете это, используя Python Application.py , теперь вы должны быть в состоянии поставить 127.0.0.1:5000 В вашем браузере и посмотрите Это инверсии Отказ

Установив Flask, мы добавили зависимость к этому компоненту, и, поскольку она должна быть состоится и воспроизводимы с согласованными зависимостями, мы должны отслеживать эту зависимость. Мы сделаем это, сделав требования .txt Файл, который будет перечислять каждую зависимость и их версию. Вы можете сделать это вручную, добавив Flask == 1.1.1 к вашему требования .txt , но я часто обманываю команду PIP Freeze> требования .txt , который перечисляет все зависимости (в вашей надежде чистой среды Python) и поместите их в файл требований.

# requirements.txt

Flask==1.1.1

Это фиктивное приложение само по себе не очень полезно, поэтому до того, как мы начнем разработать фактическое приложение, давайте определим его. Мы знаем, что цель состоит в том, чтобы иметь ресурсы, которые можно выделить, с 3 различными типами ресурсов. Для каждого типа ресурса мы хотим, чтобы следующие конечные точки (мы будем спокойны):

  • Post/{resentress_type} – создать экземпляр ресурса
  • Get/{Resource_Type} – Чтобы получить все экземпляры данного типа ресурса
  • Get/{Resource_type}/- получить определенный экземпляр
  • УДАЛЯТЬ/{Resource_type}/- Удалить определенный экземпляр ресурса
  • Post/{resentress_type}//allocations – Создание распределения для этого экземпляра ресурса
  • Get/{resentress_type}//allocations – Получить все распределения для этого экземпляра ресурса
  • Get/{Resource_type}//allocations/- Получить конкретное распределение
  • Delete/{Resource_type}//allocations/- Удалить распределение

Примечание. Resource_Type статичен, есть только 3 из них, и нет способа добавить больше из них, используя этот интерфейс, в то время как Resource_IDS и Allocation_ID являются динамическими и могут быть созданы с помощью этого интерфейса.

Теперь мы могли бы продолжить и добавить правило URL для каждого из них, чтобы применить, как такой:

from flask import Flask, jsonify

def create_application() -> Flask:
    app = Flask(__name__)

    @app.route("/", methods=['POST'])
    def create_resource_instance(resource_type):
        # Here we will create the resource instance
        return jsonify({}), 201

    # Continue making routes for all the other endpoint/method combinations
    ...

    return app

Если бы мы делали это, хотя наше Приложения .py Файл стал бы очень большим очень быстро. Кроме того, мы тогда понадобится какой-то способ различить потоки для создания интервальных ресурсов и непрерывных ресурсов (если в какой-то момент должны быть добавлены интервальные ресурсы). Вместо этого мы могли бы сделать приложение более модульно, используя чертежи колб. Чертежи позволяют нам лучше организовать и разделить наше приложение.

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

Внутри нашего invsys. каталог мы сделаем чертежи каталог с __init__.py и сделайте файл под названием onvide_resource_blueprint.py Отказ

В этот момент ваш общий каталог проекта должен напоминать это:

.
└── invsys
    ├── application.py
    ├── requirements.txt
    └── blueprints
        ├── __init__.py
        └── continuous_resource_blueprint.py

Я упомяну два способа обрабатывающую план с указанием 3 типа ресурсов.

Во-первых, мы могли бы просто создать статический план, который имеет тип ресурса в качестве динамического элемента в URL, то каждая функция маршрута должна будет подтвердить тип ресурса (возможно, используя декоратор), он может выглядеть что-то подобное:

# blueprints/continuous_resource_blueprint.py

from flask import Blueprint, jsonify

blueprint = Blueprint('ContinuousResourceBlueprint', __name__)

@blueprint.route('/', methods=['POST'])
def create_continuous_resource(resource_type):
    # Create the resource somehow
    return jsonify({}), 201

# Do the same for all the other endpoints
...

А потом в нашем application.py Мы бы зарегистрировали план настолько:

# application.py

from flask import Flask, jsonify
from blueprints.continuous_resource_blueprint import blueprint as continuous_resource_blueprint

def create_application() -> Flask:
    app = Flask(__name__)
    app.register_blueprint(continuous_resource_blueprint)
    return app

Хотя это будет работать нормально, вам нужно где-то определить приемлемые типы ресурсов, либо в среде для гибкости, либо в некотором конфиге.

Если мы знаем, что типы ресурсов вряд ли будут измениться, то было бы неплохо, чтобы они были четко указаны в application.py Отказ Один из способов сделать это, чтобы использовать создание чертежей с использованием функции, которая состояла в том, что тип ресурса использует закрытие.

Прежде чем смотреть на план, если мы посмотрим на новый Приложения .py Файл, это будет больше похоже на это:

from flask import Flask
from blueprints.continuous_resource_blueprint import create_continuous_resource_blueprint

def create_app() -> Flask:
    app = Flask(__name__)

    # Register continuous resource blueprints
    app.register_blueprint(
        create_continuous_resource_blueprint(
            blueprint_name="CarsBlueprint", # The name, used by flask when using the url_for function
            resource_type="Car", # The resource type
            resource_prefix="cars" # The base of the url for this resource type
        ),
        url_prefix='/api'
    )

    # Then do the same for lorry and truck
    ...

    return app

Преимущество вышеуказанного фрагмента заключается в том, что, глядя на мой application.py можно четко видеть, что приложение имеет непрерывный ресурс типа Автомобиль с базовым URL /машины .

Примечание в приведенном выше фрагменте я добавил URL_Prefix на зарегистрированный план. Это означает для доступа к любому из наших URL в проекте, нам нужно поставить /API. во-первых, как /API/Автомобили/Ресурсы . Я делаю это, чтобы позволить моими жителям выставлять простые UIS, используя конечные точки, которые не имеют /API. приставка. Например, я могу настроить / Чтобы вернуть простой пользовательский интерфейс, показывающий наш запас в этом приложении, но мы не будем охватывать это. В других приложениях вы можете увидеть префиксы, такие как /API/V1 И тогда они создадут новый план с префиксом /API/V2 Если они изменит функциональность службы или вынуждены добавлять некоторые обратные несовместимые изменения.

В нашем onvide_resource_blueprint.py Затем мы будем реализовать что-то вроде этого:

from flask import Blueprint

def create_continuous_resource_blueprint(blueprint_name: str, resource_type: str, resource_prefix: str) -> Blueprint:
    """
    blueprint_name: name of the blueprint, used by Flask for routing
    resource_type: name of the specific type of interval resource, such as Car or Lorry
    resource_prefix: the plural resource to be used in the api endpoint, such as cars, resulting in "/cars"
    """
    blueprint = Blueprint(blueprint_name, __name__)

    @blueprint.route(f'/{resource_prefix}', methods=["POST"])
    def create_resource():
        return jsonify({}), 201

    @blueprint.route(f'/{resource_prefix}', methods=["GET"])
    def get_resources():
        return jsonify({}), 201

    # We then do this for all the other endpoints we listed
    ...

    return blueprint

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

Как и где мы храним ресурсы и распределения?

Ну, я сказал во вступлении, что мы собираемся использовать SQLalchemy, так что это был спойлер. Мы будем хранить ассигнования и ресурсы в базе данных SQLite3 и используем SQLALCHEMY в качестве ORM для доступа к базе данных. Более конкретно мы будем использовать Flask-sqlalchemy, которую вы можете установить с помощью PIP Установить Flask-Sqlalchemy , помните, вам нужно будет обновить ваш требования .txt Файл с этой новой зависимостью.

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

Во-первых, как мы на самом деле используем и инициализируем базу данных?

В приложениях с одной файлом вы обычно увидите что-то подобное в руководствах:

# application.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///mydatabase.db"
db = SQLAlchemy(app)

# Create the models (we'll get to this after)
with app.app_context():
    db.create_all()

# Then afterwards we register routes or blueprints that we have imported
...

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

Чтобы избежать этой круговой проблемы импорта, мы просто поместите базу данных в отдельный файл. В том же каталоге, что и ваш application.py Создайте новый файл под названием База данных .py который должен выглядеть так:

# database.py

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

Тогда от нашего application.py и наши маршруты и чертежи, мы можем импортировать дБ Объект из этого модуля без проблем циркулярной зависимости.

Наше application.py теперь может выглядеть так, как правило:

from flask import Flask
from database import db

def create_app(db_uri: str) -> Flask:
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = db_uri
    # We still need to initialise the db with the flask app, but we can do this after the object has been initialised by using init_app
    db.init_app(app)

    with app.app_context():
        db.create_all()

    # Here we would then register our blueprints or routes
    ...

    return app

Общий аспект будет моделями. Это наши классы, которые представляют таблицы и последующие столбцы и отношения в базе данных.

Потому что мы будем общими, нам нужны только две таблицы. Один для представления непрерывного ресурса и один для представления непрерывного распределения ресурсов.

В Invsys Каталог создать подкаталог под названием модели с __init__.py а потом внутри нашего моделей Каталог мы создадим два новых файла, onvide_resource.py и onlice_resource_allocation.py. .

Ваш Invsys Справочник должен теперь выглядеть так:

.
├── application.py
├── requirements.txt
├── database.py
├── blueprints
│   ├── __init__.py
│   └── continuous_resource_blueprint.py
└── models
    ├── __init__.py
    ├── continuous_resource.py
    └── continuous_resource_allocation.py

Давайте посмотрим на onvide_resource.py первый. Модель AdductoreResource представляет собой автомобиль/грузовик/грузовик, поэтому каждый нам нужен столбец для типа ресурса, имени ресурса (конкретный уникальный идентификатор, который является читабельным) и UUID (также уникальным, но только 36 цифр UUID, который Несколько дублирование вроде как имя столбец, но UUID будет использоваться при работе с конечными точками). Мы добавим Создано Столбец DateTime тоже.

От AndiDiveResource будет полезно иметь возможность получить доступ ко всем выделению, связанным с этим ресурсом, поэтому мы создаем распределения отношение.

# continuous_resource.py

from database import db
import datetime

class ContinuousResource(db.Model):
    __tablename__ = "continous_resources" # Specified instead of using the default

    id = db.Column(db.String(36), primary_key=True, unique=True)
    name = db.Column(db.String(36), primary_key=True, unique=True) # Eg Car1
    resource_type = db.Column(db.String(36), primary_key=True) # Car/Lorry/Truck
    created = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow)

    # Children
    allocations = db.relationship("ContinuousResourceAllocation", back_populates="resource", lazy=True)

Теперь мы смотрим на onvide_resource_allocation.py Отказ Мы можем определить AdductiveResourceallocation как объект с from_dateTime и а to_dateTime Отказ Затем в некоторых случаях выделение может захотеть рассматривать как from_infinity или to_infinity Таким образом, мы добавим булевую колонку для этих двух вариантов и сделайте все четыре из этих столбцов Nullable. Поэтому вы можете создать распределение, пока бесконечность не будет указывать на неопределенный период обслуживания для этого ресурса, что делает его невыполнимым. Опять же, мы можем добавить тип ресурса, идентификатор и некоторые дополнительные столбцы, такие как описание, или тип выделения (например, «бронирование» или «обслуживание»). Наконец, мы добавим колонку сброса JSON для хранения любых дополнительных данных о распределении, и мы можем добавить способ свойств для возврата словарного представления, называемого «Dump».

Чтобы завершить взаимосвязь между двумя моделями, мы передаем Resource_ID связанного inverraphyResource в качестве столбца инострукций, а затем сделать отношения «ресурса».

# continuous_resource_allocation.py

from database import db
import datetime

class ContinuousResourceAllocation(db.Model):
    __tablename__ = "continuous_resource_allocations"

    id = db.Column(db.String(36), primary_key=True, unique=True)
    resource_type = db.Column(db.String(36), primary_key=True)
    created = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow)
    from_infinity = db.Column(db.Boolean, default=False)
    to_infinity = db.Column(db.Boolean, default=False)
    from_datetime = db.Column(db.DateTime, nullable=True)
    to_datetime = db.Column(db.DateTime, nullable=True)
    allocation_type = db.Column(db.String(20))
    description = db.Column(db.String(100), nullable=True)
    json_dump = db.Column(db.String(200), nullable=True)

    # Parents
    resource_id = db.Column(db.ForeignKey('continuous_resources.id'))
    resource = db.relationship('ContinuousResource', foreign_keys=resource_id)

    @property
    def dump(self) -> dict:
        try:
            return json.loads(self.json_dump)
        except:
            return {}

У нас есть наши модели, теперь что?

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

Давайте посмотрим на первый взгляд, где в нашем план, мы употребляем модели и базу данных напрямую.

Наше onvide_resource_blueprint.py Может начать выглядеть так (Примечание: мы ничего не возвращаем из наших функций конечной точки, мы доберемся до этого):

from flask import Blueprint
from database import db
from models.continuous_resource import ContinuousResource
import uuid

def create_continuous_resource_blueprint(blueprint_name: str, resource_type: str, resource_prefix: str) -> Blueprint:
    """
    blueprint_name: name of the blueprint, used by Flask for routing
    resource_type: name of the specific type of interval resource, such as Car or Lorry
    resource_prefix: the plural resource to be used in the api endpoint, such as cars, resulting in "/cars"
    """
    blueprint = Blueprint(blueprint_name, __name__)

    @blueprint.route(f'/{resource_prefix}', methods=["POST"])
    def create_resource():
        new_resource = ContinuousResource(id=str(uuid.uuid4()), **request.get_json()) # We assume request has everything we need in it for now
        db.session.add(new_resource)
        db.session.commit()
        return jsonify({}), 201

    @blueprint.route(f'/{resource_prefix}', methods=["GET"])
    def get_resources():
        resources = ContinuousResource.query.filter_by(resource_type=resource_type)
        return jsonify({}), 201

    # We then do this for all the other endpoints we listed
    ...

    return blueprint

Если вы посмотрите на вышеуказанный фрагмент, вы увидите, что мы упоминаем базу данных и модели. Для некоторых приложений это нормально, но представьте, что мы позже решили изменить, какую базу данных мы используем. Или мы изменим нашу ORM. Это означает, что все наши ссылки базы данных в наших чертежах и маршрутах потребуют обновления. Это означает, что ваши чертежи «связаны» с нашей базой данных.

Второй подход пытается разделить чертежи от с использованием концепции, знают как DAOS (объекты доступа к данным) или DALL (слои доступа к данным).

Мы создадим DAO, который будет использоваться для обработки любых связанных баз данных для непрерывных ресурсов (включая ассигнования). Дао будет инкапсулировать логику базы данных. Поэтому, если мы хотим мигрировать базу данных, нам просто нужно обновить DAO и ничего, что потребуется дао, нужно будет коснуться.

Возможно, вы думаете: «Почему вам нужно будет мигрировать базы данных?». Ну, пока наши модели достаточно. Но представьте, что оказывается, что наши клиенты API, любят сбрасывать большие суммы JSON в нашем столбце «JSON_Dump», и, возможно, в будущем они могут захотеть иметь возможность получить ассигнования на основе определенных данных в этой колонке. В этом случае это может иметь смысл изменить нашу базу данных из SQL к чему-то вроде MongoDB, который обрабатывает JSON более чем народ. Наш Дао дает нам гибкость, чтобы адаптироваться к тому, как наш сервис потребляется без реальной стоимости дополнительной разработки.

В Invsys Мы создадим новый каталог под названием даос с __init__.py , а затем файл DAO под названием onvide_resource_dao.py Отказ

Наш каталог теперь выглядит так:

.
├── application.py
├── requirements.txt
├── database.py
├── blueprints
│   ├── __init__.py
│   └── continuous_resource_blueprint.py
├── daos
│   ├── __init__.py
│   └── continuous_resource_dao.py
└── models
    ├── __init__.py
    ├── continuous_resource.py
    └── continuous_resource_allocation.py

Наш DAO – это просто класс, содержащий статические методы для каждой связанной с базой данных

# continuous_resource_dao.py

from database import db
from typing import List
from models.continuous_resource import ContinuousResource
import uuid

class ContinuousResourceDao:
    @staticmethod
    def create_resource(resource_type, name) -> ContinuousResource:
        resource = ContinuousResource(
            id=str(uuid.uuid4()),
            resource_type=resource_type,
            name=name
        )
        db.session.add(resource)
        db.session.commit()
        return resource

    @staticmethod
    def get_resources(resource_type) -> List[ContinuousResource]:
        return ContinuousResource.query.filter_by(resource_type=resource_type)

    # There will be more functions for each other query
    ...

А затем в нашем проекте, мы используем DAO вместо прямой базы данных доступ

# continuous_resource_blueprint.py

from flask import Blueprint, request, jsonify
from daos.continuous_resource_dao import ContinuousResourceDao

def create_continuous_resource_blueprint(blueprint_name: str, resource_type: str, resource_prefix: str) -> Blueprint:
    """
    blueprint_name: name of the blueprint, used by Flask for routing
    resource_type: name of the specific type of interval resource, such as Car
    resource_prefix: the plural resource to be used in the api endpoint, such as cars, resulting in "/cars"
    """
    blueprint = Blueprint(blueprint_name, __name__)

    @blueprint.route(f'/{resource_prefix}', methods=["POST"])
    def create_resource():
        resource = ContinuousResourceDao.create_resource(
            resource_type=resource_type,
            name=request.get_json(force=True)['name']
        )
        return jsonify({}), 201

    @blueprint.route(f'/{resource_prefix}', methods=["GET"])
    def get_resources():
        resources = ContinuousResourceDao.get_resources(resource_type=resource_type)
        return jsonify({}), 200

        # Then all the other endpoints
        ...

    return blueprint

Возможно, вы думаете: «Какова точка создания DAO, чтобы отделить слой базы данных из маршрутов, если вы тогда возвращаете из DAO объекта в сочетании с базой данных?». Его действительный вопрос, наш DAO возвращает экземпляры модели (или их списки), что означает, что мы технически не отделены. К счастью, объекты, которые мы возвращаем, имеют тот же интерфейс, что и любой пользовательский, который мы сделаем, поэтому на данный момент это не вызывает никаких проблем. В будущем, если вы должны были решить, что вы хотели использовать MongoDB, то вам нужно будет иметь промежуточные объекты DAO Spawn с тем же интерфейсом, но это не должно влиять на что-то, что потребляет дао.

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

Мы не можем напрямую вернуть эти объекты в нашем API. Наш API возвращает JSON. Таким образом, вместо этого мы можем создавать словарные представления этих объектов и позволяют колбу возвращать их как JSON, используя jsonify функция. Таким образом, каждый объект нужен сериализатор.

Мы можем создать новый каталог под названием сериал с __init__.py И мы создадим сериализатор для каждой модели. Итак, мы создаем onvide_resource_serialiser.py. и onvide_resource_allocation_serialiser.py. .

Каталог теперь выглядит так:

.
├── application.py
├── requirements.txt
├── database.py
├── blueprints
│   ├── __init__.py
│   └── continuous_resource_blueprint.py
├── daos
│   ├── __init__.py
│   └── continuous_resource_dao.py
├── models
│   ├── __init__.py
│   ├── continuous_resource.py
│   └── continuous_resource_allocation.py
└── serialisers
    ├── __init__.py
    ├── continuous_resource_allocation_serialiser.py
    └── continuous_resource_serialiser.py

Serialiser принимает экземпляр объекта и возвращает словарь с серийными типами данных. Так что в наших сериалах нам нужно преобразовать datetimes в Строки остальное мы столкнемся с проблемами, используя jsonify . Примечание. Наши «Serialisers» возвращают словари, они не являются сериалами в самой простой форме. Существуют некоторые модули для колбы, которые могут быть использованы для определения классов сериала, основанные на классах модели, но это не очень хорошо работает с гибкостью нашего DAO. Он также парит объекты базы данных со своим внешним представлением, что является чем-то, чтобы избежать.

# continuous_resource_serialiser.py

class ContinuousResourceSerialiser:
    @staticmethod
    def serialise(resource) -> dict:
        return {
            'id': resource.id,
            'name': resource.name,
            'resource_type': resource.resource_type,
            'created': resource.created.strftime("%Y-%m-%dT%H:%M:%S")
        }

а также:

# continuous_resource_allocation_serialiser.py

class ContinuousResourceAllocationSerialiser:
    @staticmethod
    def serialise(allocation) -> dict:
        return {
            'id': allocation.id,
            'resource_type': allocation.resource_type,
            'resource_id': allocation.resource_id,
            'from_infinity': allocation.from_infinity,
            'to_infinity': allocation.to_infinity,
            'from_datetime': (
                allocation.from_datetime.strftime("%Y-%m-%dT%H:%M:%S")
                if allocation.from_datetime
                else None
            ),
            'to_datetime': (
                allocation.to_datetime.strftime("%Y-%m-%dT%H:%M:%S")
                if allocation.to_datetime
                else None
            ),
            'allocation_type': allocation.allocation_type,
            'description': allocation.description,
            'dump': allocation.dump
        }

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

# continuous_resource_blueprint.py

from flask import Blueprint, request, jsonify
from daos.continuous_resource_dao import ContinuousResourceDao
from serialisers.continuous_resource_serialiser import ContinuousResourceSerialiser

def create_continuous_resource_blueprint(blueprint_name: str, resource_type: str, resource_prefix: str):
    """
    blueprint_name: name of the blueprint, used by Flask for routing
    resource_type: name of the specific type of interval resource, such as boy bay or payload bay
    resource_prefix: the plural resource to be used in the api endpoint, such as bot_bay, resulting in "/bot_bays"
    """
    blueprint = Blueprint(blueprint_name, __name__)

    @blueprint.route(f'/{resource_prefix}', methods=["POST"])
    def create_resource():
        resource = ContinuousResourceDao.create_resource(
            resource_type=resource_type,
            name=request.get_json(force=True)['name']
        )
        return ContinuousResourceSerialiser.serialise(resource), 201

    @blueprint.route(f'/{resource_prefix}', methods=["GET"])
    def get_resources():
        return jsonify([
            ContinuousResourceSerialiser.serialise(resource)
            for resource in ContinuousResourceDao.get_resources(resource_type=resource_type)
        ]), 200

Обратите внимание, что мы используем 201 в качестве кода состояния, если что-то было создано, и 200 в случаях, когда запрос в порядке, но ничего не создается.

Вам нужно будет заполнить пробелы для всех остальных конечных точек, которые у меня сложились другие (посмотрите на исходный код в репо).

Теперь мы посмотрим вместе с функцией создания нового распределения, потому что эта функция должна подтвердить, что можно сделать выделение.

Для создания ассигнований у нас будет маршрут, напоминающий:

@blueprint.route(f'/{resource_type}//allocations', methods=['POST'])
def create_resource_allocation(resource_id):
    ...

В этом create_resource_allocation Функция, мы должны иметь характеристики распределения в тело полезной нагрузки, и то, что мы намерены сделать, это дисквалифицировать распределение. Наша функция проверит условия, чтобы увидеть, сможем ли мы отклонить этот запрос из-за перекрытий или других условий, и если мы не будем дисквалифицировать его, мы создадим запись распределения.

@blueprint.route(f'/{resource_type}//allocations', methods=['POST'])
def create_resource_allocation(resource_id):
    # Clean the inputs

    # Get all existing allocations related to this resource id

    # Check each existing allocation and if there is overlap, reject this request

    # Create the allocation if it passed the above checks
    ...

Так что написано так, совершенно ясно, что мы должны сделать. Но когда мы считаем, что наше распределение определяется четырьмя ненугими значениями, это означает, что наша функция в конечном итоге в конечном итоге в конечном итоге, состоящая в том, что наши несколько операторов ELIF-ELIF-ELIF. Я не буду ставить фактическую функцию здесь, но вы можете посмотреть на это в onvide_resource_blueprint.py Линия 58 Отказ

Предполагая, что вы создали все, что мы упомянули выше, и заполнены пробелами, или что вы клонировали репозиторий. Если вы запустите Python Application.py Теперь вы должны быть в состоянии нацелить приложение для создания ресурсов и ассигнований с населенными ответами.

Если вы откроете почтальон и опубликую новый экземпляр автомобиля к 127.0.0.1:5000/API/CARS , вы должны получить ответ, содержащий тело запроса и новый UUID.

Мы можем получить автомобиль, используя Get 127.0.0.1:5000/API/CARS Отказ

Вы можете опубликовать распределение:

Это работает просто нормально, но предполагает, что у вас есть среда Python, настроенная правильно. Мы можем избежать этой проблемы, запустив приложение в контейнере докера. Что нам нужно сделать, это создать DockerFile, которая будет использоваться для создания докера изображения нашего приложения, а затем вы можете использовать Docker для запуска изображения в контейнере.

В Invsys каталог Создайте файл под названием Dockerfile Отказ Наш DockerFile будет выглядеть так:

# Dockerfile

FROM python:3.7-alpine
COPY requirements.txt /
RUN pip install -r /requirements.txt
COPY . /app
WORKDIR /app
EXPOSE 5001
CMD [ "python", "application.py" ]

Мы используем Из Python: 3.7-Alpine Как наша база, поскольку у него есть правильная версия Python и альпийский Изображения относительно невелики по сравнению с нельпыми изображениями (несколько мегабийцев в отличие от нескольких сотен мегабайт). Мы Скопируйте требования. Atxt/ что делает файл доступен в нашем образе докера, а затем установить его, используя Запустите PIP Установить -r/requirement.txt Отказ Затем мы скопируем остальную часть нашего исходного кода в подкаталог под названием приложение с Копировать./приложение Отказ Использование Workdir/app. означает, что следующие команды будут выполнены в этом каталоге. Мы Выкрыть 5001 Чтобы выставить порт 5001, который является портом, определенным в нашем application.py Отказ Затем, наконец, мы утвердим команду, чтобы запустить приложение, которое является CMD [«Python», «Application.py»] Отказ

Когда вы запускаете приложение без Docker, он создаст базу данных в каталоге Invsys под названием red.db (В нашем Если в application.py , мы пройдем sqlite:///red.db Как DB_URI, а если оно не существует, SQLalchemy создает его для нас). Это означает, что когда вы создаете свой образ докера, у вас уже будет ваша база данных на вашем изображении с любыми существующими данными в нем. Поэтому избегайте этого, добавив .Dockerignore Файл в свой каталог, содержащий red.db. . Теперь, когда вы создаете свое изображение, будет свежая база данных. Для этого проекта мы не обеспокоены настойчивостью и объемами базы данных.

Теперь, когда у нас есть DockerFile (и наш .Dockerignore), мы можем построить изображение, используя Docker Build -T Invsys. , который построит изображение под названием Invsys Исходя из Dockerfile в нашем текущем каталоге ( . ).

Затем вы можете развернуть ваше приложение, используя Docker Run -P 5001: 5001 Invsys и нацеливаться на то же самое, что и прежде чем использовать почтальон. -P 5001: 5001 Для маршруты порта докера в порт нашего контейнера.

Приложение шлюза

Почему нам нужно один?

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

Что будет делать?

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

Давай сделаем это

Внутри нашего главного каталога проекта создайте новый каталог под названием шлюз . CD в этот каталог. Мы создадим здесь другое приложение для колба, хотя это будет намного проще. Создать application.py Опять же, создайте еще одну свежую среду Python и снова установите колбу. Создать требования .txt опять таки. Ваша общая структура каталогов проекта должна выглядеть так:

.
├── gateway
│   ├── application.py
│   └── requirements.txt
└── invsys
    ├── Dockerfile
    ├── application.py
    ├── database.py
    ├── requirements.txt
    ├── blueprints
    │   ├── __init__.py
    │   └── continuous_resource_blueprint.py
    ├── daos
    │   ├── __init__.py
    │   └── continuous_resource_dao.py
    ├── models
    │   ├── __init__.py
    │   ├── continuous_resource.py
    │   └── continuous_resource_allocation.py
    └── serialisers
        ├── __init__.py
        ├── continuous_resource_allocation_serialiser.py
        └── continuous_resource_serialiser.py

Опять же, прежде чем разработать приложение, давайте немного определим его дальше.

Определение

Для демонстрационных целей мы будем только справиться только два Invsys конечные точки для маршрутизации. Таким образом, наше приложение будет принимать запросы:

  • Post/API/{Resource_type}
  • Get/API/{Resource_Type}

Мы ожидаем, что наше приложение получит запрос от клиента API, пересылать строки полезной нагрузки или запроса в Invsys Затем вперед ответ от Invsys Вернуться к клиенту API.

На данный момент из-за минимальных требований мы пропустим с помощью чертежей и развиваемся непосредственно в нашем application.py Отказ Вы также заметите, что у нас нет необходимости в настоящее время для любой базы данных. Так что нет моделей или даос. Нам не понадобится сериал, потому что мы просто пересылаем ответы.

Разработка

Наше application.py может иметь свои маршруты, определенные следующим образом:

# application.py

from flask import Flask

def create_application():
    app = Flask(__name__)

    @app.route('/api/', methods=['POST'])
    def post_resource(resource_type):
        ...

    @app.route('/api/', methods=['GET'])
    def get_resources(resource_type):
        ...

    return app

Переслать наши запросы, мы будем использовать Запросы Модуль, который может установить с помощью PIP Установка запросов Отказ Не забудьте добавить это на ваш требования .txt Отказ

Глядя на наш post_resource Функция сначала мы хотим принять полезную нагрузку из входящего запроса и переслать ее в экземпляр нашего Invsys Отказ Если мы развернули Invsys на 127.0.0.1 Тогда мы могли бы использовать:

import requests

data = ... # from request
resource_type = ... # from endpoint
response = requests.post(f"http://127.0.0.1:5000/api/{resource_type}", data)

Но, делая это, наш исходный код приложения сочетается с тем, как и где мы развертываем Invsys Отказ Так вместо этого мы можем опубликовать до http://invsys: 5000/API/... и убедитесь, что наша сеть установлена на маршрут Invys -> 127.0.0.1 или к тому, на какой IP он принимается.

Таким образом, наше приложение может начать выглядеть так:

# application.py

from flask import Flask, request, Response
from typing import List, Tuple
import json
import requests

def create_application():
    app = Flask(__name__)

    @app.route('/api/', methods=['POST'])
    def post_resource(resource_type):
        # Get the payload from our incoming request
        payload = request.get_json(force=True)

        # Forward the payload to the relevant endpoint in invsys
        response = requests.post(f'http://invsys:5000/api/{resource_type}', data=json.dumps(payload))

        # Forward the response back to the client
        # We create a Response object by deconstructing our response from above
        return Response(response.content, response.status_code, get_proxy_headers(response))

    @app.route('/api/', methods=['GET'])
    def get_resources(resource_type):
        # There is no payload and no querystrings for this endpoint in invsys
        response = requests.get(f'http://invsys:5000/api/{resource_type}')

        # Forward the response back to the client
        # We create a Response object by deconstructing our response from above
        return Response(response.content, response.status_code, get_proxy_headers(response))

    return app

def get_proxy_headers(response) -> List[Tuple]:
    # A function to get the needed headers from the requests response
    excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection']
    headers = [
        (name, value)
        for (name, value) in response.raw.headers.items()
        if name.lower() not in excluded_headers
    ]
    return headers

И это все, что есть для этого для нашего ворота приложения. Мы добавим тот же DockerFile, но вместо этого выставляем порт 5001. В нашем application.py и мы установим порт 5001 В нашем Если блокировать.

Мы не можем просто развернуть это приложение, используя только Python Application.py Потому что вам нужен экземпляр Invsys Бег, и вам нужна ваша сеть, настроен на маршрут Invsys к правильному IP-адресу.

К счастью, Докер может помочь нам с этим.

Составление нашей системы

У нас есть два колбовых приложения. Invsys и шлюз. Мы хотим, чтобы они оба были развернуты, и мы хотим, чтобы ворота могли отправлять запросы в Invsys, используя Invsys вместо конкретного IP.

Docker-Compose – это инструмент, который позволяет нам определить развертывание нескольких контейнеров и имеет дополнительное преимущество изготовления каждого контейнера, ориентированного с использованием имени контейнера. Все, что нам нужно, чтобы создать Docker-Compose.yaml В нашем главном каталоге проекта, который сейчас выглядит так:

.
├── docker-compose.yaml
├── gateway
│   ├── Dockerfile
│   ├── application.py
│   └── requirements.txt
└── invsys
    ├── Dockerfile
    ├── application.py
    ├── database.py
    ├── blueprints
    │   ├── __init__.py
    │   └── continuous_resource_blueprint.py
    ├── daos
    │   ├── __init__.py
    │   └── continuous_resource_dao.py
    ├── models
    │   ├── __init__.py
    │   ├── continuous_resource.py
    │   └── continuous_resource_allocation.py
    ├── requirements.txt
    └── serialisers
        ├── __init__.py
        ├── continuous_resource_allocation_serialiser.py
        └── continuous_resource_serialiser.py

И наше Docker-Compose.yaml Похоже:

# docker-compose.yaml

version: '2'
services:
    gateway:
        build: gateway
        ports:
            - "5001:5001"
    invsys:
        build: invsys

Мы определили две услуги. Один для шлюзов и один для инверсий. Ключ, который мы используем как имя сервиса, – это имя, используемое для нацеления этого обслуживания в сети. Как мы называем нашу службу invsys как Invsys Любые запросы из нашего приложения, целью Invsys будет направлен на правильный IP для этой услуги. Мы используем построить Флаг в каждом случае, что означает, что инструмент будет искать шлюз и Invsys подкаталогии и используйте их DockerFiles для создания изображения. Флаг порта такой же, как тот, который используется в Docker Run Команда, она направляет внешний порт докера на внутренний открытый порт наших контейнеров. Вы заметите, что мы не добавили отображение порта для Invsys И это потому, что мы хотим заставить просьбы пройти через шлюз. Если вы хотели уметь нацелиться Invsys Прямо тоже вам нужно было бы добавить Порты: - "5000: 5000" Отказ

Теперь вы можете развернуть приложение, запустив Docker-Compose up Отказ Использование Docker-Compose, ваше приложение, вероятно, не будет размещено на 127.0.0.1, так что вы можете получить правильный IP, используя Docker-Machine IP (Вам может потребоваться запустить Дочсерва-машина начать первым, и даже Eval $ (Docker-Machine Eng по умолчанию) Чтобы правильно установить конфигурацию вашей упаковки машины). Затем в Postman вы можете проверить ваши запросы на {revent_ip}: 5001/API/Автомобили который должен целена с воротами и направлять запросы в Invsys. Вы можете закончить свое развертывание, используя Ctrl-C. Если вы хотите развернуть на заднем плане, используйте Docker-Compose -D UP И закончить использование вашего развертывания Docker-Compose Down Отказ

С нашей приложением развернуто, мы можем опубликовать новый автомобиль через шлюз (обратите внимание на хост и порт запроса)

Что дальше?

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

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

Показывая потенциальный поток администратора:

Показывая потенциальный поток пользователя:

И оттуда вам понадобится какая-то внешняя интеграция с поставщиками или гаражами автомобилей. Но это за пределами нашей области.

Развертывание на местном без докера

Хотя это руководство ориентировано на развертывание с Docker, вы можете развернуть на местном без него тоже. Настройте свою сеть на маршрут Invsys -> 127.0.0.1 Обновление вашего /etc/hosts Файл с дополнительной строкой, как 127.0.0.1 Invsys Отказ Затем вы можете открыть две оконные окна. Во-первых, CD к Invsys а потом беги Python Application.py и в другом окне терминала делайте то же самое, но в Шлюз каталог. Тогда с почтальоном вы можете нацелить либо Backend On 127.0.0.1 Отказ Докер больше, чем просто развертывание, поэтому этот подраздел – это просто для тех, кто заинтересован.

Другие вещи, которые следует учитывать

В этом руководстве заложены несколько вещей:

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

Оригинал: “https://dev.to/reritom/creating-an-application-comprising-of-multiple-flask-apps-deployed-using-docker-compose-3b1j”