Перейти до основного вмісту

Стрімер

інформація

Документ "Стрімер" відповідає за роботу з http запитами, які містять файли. Він визначає шляхи (маршрути) для обробки різних типів запитів і відповідних їм дій. Кожен маршрут описується в форматі REST API, що дозволяє чітко визначити структуру та тип запиту, а також обробник (контролер), який буде виконувати логіку для цього маршруту.

Архітектура

При необхідності опису маршрутів з отриманням файлів, в предметній області необхідно створити документ "Стрімер" з переліком необхідних маршрутів.

Документ "Стрімер" повинен бути зареєстрований в документі "Реєстр" предметної області, який в свою чергу, має бути зареєстрований в відповідному сервісі, включеному до бізнес-схеми. Це гарантує, що при запуску ядра обчислень будуть завантажені всі маршрути маршрутизатора. При виклику та виконанні конкретного обробника запиту ядро обчислень надасть актуальний знімок структури бізнес-схеми, де вже наявний опис кінцевого маршруту разом з його обробником.

streamer-arch.svg

Структура URL

Загальна маска url:

Метод: HTTP метод.
Шлях: {protocol}://${host}:${port}/{baseUrl}/:{service}/:${domain}/:${version}/:${endpoint}/:${dynamic-parameter-n}?{query-parameter-n}
Заголовки: Обʼєкт з переліком заголовків.

де:

  • protocol - тип протоколу (обовʼязково).
  • host - назва хосту (обовʼязково).
  • port - номер порту (обовʼязково).
  • baseUrl - базовий маршрут, який описується в конфігурації сервера. За замовчуванням /v1/call/stream/ (обовʼязково).
  • service - назва сервісу (обовʼязково).
  • domain - предметна область (обовʼязково).
  • version - версія кінцевого маршруту (обовʼязково).
  • endpoint - назва кінцевого маршруту (обовʼязково).
  • dynamic-parameter-n - динамічні параметри (опціонально).
  • query-parameter-n - query параметри (опціонально).
  1. Приклад запиту користувача по його унікальному ідентифікатору:
GET
http://0.0.0.0:11001/v1/call/stream/BusinessAdmin/BusUsers/v1/get-one/f47ac10b-58cc-4372-a567-0e02b2c3d479
  1. Приклад запиту користувачів з сортуванням по даті створення записів та з лімітом в 5 записів.
Метод: GET
http://0.0.0.0:11001/v1/call/stream/BusinessAdmin/BusUsers/v1/find-many?order=desc&limit=5

Склад

Маршрут стрімера складається з опису деталей маршруту, лімітів попередньої обробки файлів та кінцевого обробника цього маршруту. X-Fiber фокусується на явному описі контролю над маршрутом надаючи можливість описувати схему валідації вхідних параметрів маршруту. Такими елементами маршруту є динамічні параметри, query параметри та заголовки.

Загальна структура маршрутизатора

type HttpMethod = 
| "GET"
| "POST"
| "PUT"
| "PATCH"
| "DELETE"
| "OPTIONS"
| "HEAD"
| "TRACE";

type AuthScope = 'public:route' | 'private:user' | 'private:system'
type Version = "v1" | "v2" | "v3" | "v4" | "v5" | string;

type RouteParams = {
name: string;
scope: "required" | "optional";
};

type HeaderParams = {
name: string;
scope: "required" | "optional";
};

type QueryParameter =
| "string"
| "string[]"
| "number"
| "number[]"
| "boolean"
| "boolean[]";

type QueryParams = {
name: string;
format: QueryParameter[];
scope: "required" | "optional";
};

type StreamLimits = {
fieldNameSize?: number;
fieldSize?: number;
fields?: number;
fileSize?: number;
parts?: number;
};

type StreamResponse = {
// ... response structure
}

type StreamHandler = (
...args // arguments
) => Promise<StreamResponse | void>

export type StreamStructure<S extends string = string> = {
[key in S]: {
scope?: AuthScope;
version?: Version;
method?: Pick<HttpMethod, 'GET' | 'POST' | 'PUT' | 'DELETE'>
params?: RouteParams[];
headers?: HeaderParams[];
queries?: QueryParams[];
limits?: StreamLimits
handler: StreamHandler;
};
};

де:

  • Типи:
    • AuthScope - перелік типів приватизації.
    • Version - тип версії.
    • RouteParams - тип динамічного параметра кінцевого маршруту.
    • HeaderParams - тип заголовка кінцевого маршруту.
    • QueryParameter - тип query параметра кінцевого маршруту.
    • StreamHandler - структура обробника запиту.
    • StreamStructure - структура документа "Стрімер".
  • Структури обʼєкта маршруту:
    • key - строкове представлення назви кінцевого маршруту.
    • scope - тип приватизації кінцевого маршруту.
    • version - версія кінцевого маршруту.
    • method - спрощений перелік можливих http методів.
    • params - динамічні параметри, які передаються в url.
    • headers - заголовки, які передаються разом з запитом.
    • queries - query параметри, які передаються в url.
    • limits - опис лімітів на приймання файлів.
    • handler - обробник запиту.
небезпека

X-Fiber перевіряє назви кінцевих маршрутів, які не повинні мати слеш або крапку, а при потребі створення назви кінцевого маршруту використовуйте slug або на худий кінець - camelCase. В разі наявності в кінцевому маршруті слешу або крапки ядро обчислень при завантаженні схеми видасть помилку з вказанням на місце розташування кінцевого маршруту в бізнес-схемі.

інформація

Опис кінцевого маршруту складається з опису динамічних параметрів маршруту, query параметрів, заголовків, типу приватизації та версії маршруту. X-Fiber надає можливість валідації деталей маршрутизації, завдяки яким на етапі отримання запиту, адаптер http протоколу ядра обчислень проведене необхідні перевірки. Ліміти обробки файлів відносяться до логіки попередньої обробки та входять до опису обробки запиту.

Деталі маршруту

Деталі маршруту складаються з:

  1. http метод обробки файлів (за замовчуванням POST).
  2. Версії кінцевого маршруту (за замовчуванням v1),
  3. Типу приватизації (за замовчуванням public:route),
  4. Динамічних параметрів (за замовчуванням пустий масив),
  5. Query параметрів (за замовчування пустий масив),
  6. Заголовки (за замовчуванням пустий масив).

Метод обробки файлів

інформація

Маніпуляції глобально поділяються на 4 аспекти - отримати, створити, змінити та видалити. Зважаючи на це X-Fiber надає доступ до створення кінцевих маршрутів з використанням типів http методів підпадаючи під цей перелік задач.

За замовчуванням кінцевому маршруту присвоюється метод POST.

Версія

інформація

Версія кінцевого маршруту дозволяє відокремити минулі реалізації кінцевих маршрутів з якими працюють відповідні джерела взаємодії від нової, що спрощує підтримку API без потреби створювати кінцеві маршрути аналогічного призначення з словами синонімами.

За замовчуванням кінцевому маршруту присвоюється версія v1. Окремо варто підкреслити, що версії потрібно вказувати v1 / v2 / v3 / v4 і т.д.

Тип приватизації

Тип приватизації визначає, чи потребує маршрут автентифікації та даних сесії, яка вже зберігається на сервері. З розрахунку типу приватизації випливає можлива структура контексту виконання запиту. Так, для приватних кінцевих маршрутів контекст буде містити ще й дані про сесію.

X-Fiber підтримує наступні типи приватизації:

export type AuthScope = "public:route" | "private:user" | "private:system";

де:

  • public:route: Цей тип приватизації використовується для публічних маршрутів, які доступні для всіх користувачів без обмежень.
  • private:user: Цей тип приватизації застосовується до запитів, що відносяться до конкретного користувача. Для цього типу потрібні відповідні токени доступу користувача для аутентифікації та авторизації, які повинні надходити в заголовках запиту.
  • private:system: Цей тип приватизації використовується для системних запитів, які взаємодіють зі службами або компонентами системи. Для цього типу також потрібні відповідні системні токени доступу, які повинні надходити в заголовках запиту.
інформація

Залежно від типу приватизації, http адаптер ядра обчислень формує відповідний контекст виконання, що враховує наявність відповідних токенів доступу, окрім випадку з public:route. Деталі структури контексту виконання обробника запиту описані в "Обробник запиту"

Динамічні параметри

Динамічні параметри використовуються при необхідно надання інформації за унікальними класифікаторами сутностей - ідентифікатор, імен тощо.

import { setStreamer, StreamRequest, Context, Agents, StreamResponse } from 'x-fiber/proton'

type GetOnePrams = {
userId: 'required'
}

export const BusUsersAggStreamer = setStreamer<'getOne'>({
getOne: {
method: 'GET',
params: [
{
name: 'userId',
scope: 'required',
},
{
name: 'partnerId',
scope: 'optional',
},
],
handler: async (
request: StreamRequest<void, GetOnePrams>,
agents: Agents,
context: Context
): Promise<StreamResponse> => {
// ... route business logic
},
},
});

де:

  • params - обʼєкт опису динамічних параметрів.
  • name - назва параметра, якому буде присвоєне значення в request.params.
  • scope - обовʼязковість параметра. Якщо scope = required, то адаптер протоколу поверне помилку про відсутність такого параметра в структурі маршруту запиту. Якщо optional, в разі відсутності буде присвоєно в request.params значення null до відповідної назви заголовку.

В разі виявлення помилки валідації адаптер http протоколу поверне наступну помилку:

{
"type": "fail",
"code": "0002.0001.0005",
"message": "Dynamic parameter '{dynamic-param-name}' is required."
}
warning

Перелік обʼєктів грає важливу роль! Послідовність аргументів визначає який аргумент з url буде присвоєний якому значенню.

Опис динамічних та сталих параметрів X-Fiber сприймає як динамічні, тому в разі потреби опису сталого параметру - включайте його в загальний опис в необхідній послідовності

Query параметри

Query параметри використовуються для опису умов виконання запиту. Такими умовами можуть бути - фільтрація, пагінація, визначення лімітів на кількість записів тощо. X-Fiber надає можливість не тільки здійснює валідацію query параметрів, а й перетворює значення в описаний тип.

import { setStreamer, StreamRequest, Context, Agents, StreamResponse } from 'x-fiber/proton'

type GetOneQueries = {
limit: 'required'
sort: 'optional',
}

export const BusUsersAggStreamer = setStreamer<'getOne'>({
getOne: {
method: 'GET',
queries: [
{
name: 'limit',
format: 'number',
scope: 'required',
},
{
name: 'sort',
format: 'string',
scope: 'optional',
},
],
handler: async (
request: StreamRequest<void, void, GetOneQueries>,
agents: Agents,
context: Context
): Promise<StreamResponse | void> => {
// ... route business logic
},
},
});

де:

  • queries - обʼєкт опису query параметрів.
  • name - назва query параметру, якому буде присвоєне значення в request.queries.
  • format - тип даних параметру, до якого потрібно привести. Підтримуються наступні типи: string, string[], number, number[], boolean, boolean[].
  • scope - обовʼязковість параметра. Якщо required, то адаптер протоколу поверне помилку про відсутність такого параметра в структурі маршруту запиту. Якщо optional, в разі відсутності буде присвоєно в request.queries значення null до відповідного ключа динамічного параметра.

В разі виявлення помилки валідації адаптер http протоколу поверне наступну помилку:

{
"type": "fail",
"code": "0002.0001.0006",
"message": "Query parameter '{query-param-name}' is required."
}

Заголовки

Заголовки маршруту використовуються як додаткова інформація про запит, такі як керування кешуванням, визначення формату даних, встановлення параметрів безпеки, ідентифікації клієнта на сервері тощо. X-Fiber надає можливість валідації необхідних заголовків.

import { setStreamer, StreamRequest, Context, Agents, StreamResponse } from 'x-fiber/proton'

type GetOneHeaders = {
'etag': 'required'
}

export const BusUsersAggStreamer = setStreamer<'getOne'>({
getOne: {
method: 'GET',
headers: [
{
name: 'etag',
scope: 'required',
},
],
handler: async (
request: StreamRequest<void, void, void, GetOneHeaders>,
agents: Agents,
context: Context
): Promise<StreamResponse> => {
// ... route business logic
},
},
});

де:

  • headers - обʼєкт опису заголовків.
  • name - назва заголовка, якому буде присвоєне значення в request.headers.
  • scope - обовʼязковість параметра. Якщо required, то адаптер протоколу поверне помилку про відсутність такого заголовка в структурі маршруту запиту. Якщо optional, в разі відсутності буде присвоєно в request.headers значення null до відповідної назви заголовка.

В разі виявлення помилки валідації адаптер http протоколу поверне наступну помилку:

{
"type": "fail",
"code": "0002.0001.0004",
"message": "Header '{header-name}' is required."
}

Попередня обробка

Попередня обробка файлів визначається лімітами на кількість файлів, які можуть бути прийняті за один раз, а також розмір окремого файлу. Ліміти визначаються як глобально, описуючи конфігураційні значення, так і локально - описуючи значення в конкретному маршруті стрімера.

Створення глобальних лімітів описуються в конфігурації запуску ядра обчислення в розділі "Вступ", та мають аналогічний перелік складових як і в локальних лімітах. Локальні ліміти виставляються наступним чином:

import { setStreamer, StreamRequest, Context, Agents, StreamResponse } from 'x-fiber/proton'


export const BusUsersAggStreamer = setStreamer<'getOne'>({
getOne: {
GET: {
limits: {
fileSize: 10 * 1024 * 1024, // 10 Mb,
parts: 3,
},
handler: async (
request: StreamRequest,
agents: Agents,
context: Context
): Promise<StreamResponse> => {
// ... route business logic
},
},
},
});

де:

  • limits - обʼєкт опису локальних лімітів
  • fileSize - розмір одного файлу, який надається в байтах.
  • parts - допустима кількість завантаження файлів за один раз.

При перевищенню лімітів, адаптер протоколу надасть відповідь на запит:

{
"type": "fail",
"code": "0002.0001.0013",
"message": "Request file 'IMG_9265.PNG' with mimetype 'image/png' too large.",
"limits": {
"fileSize": 10,
"parts": 3
}
}

де:

  • IMG_9265.PNG - назва файлу.
  • image/png - MIME-type файлу.

Обробник запиту

Обробник запиту являє собою асинхронну функцію, яка складається з 3х аргументів та або нічого не повертає, або повертає певну структуру відповіді, яка при обробці запиту перетворюється в структуру відповіді на запит.

import { StreamRequest, Agents, Context, StreamResponse } from 'x-fiber/proton'

export type StreamHandler = (
request: StreamRequest,
agents: Agents,
context: Context
) => Promise<StreamResponse | void>;

де:

  • StreamRequest - обʼєкт запиту.
  • Agents - перелік агентів функціональності.
  • Context - контекст виконання запиту.
  • StreamResponse - тип відповіді на запит.
інформація

X-Fiber пропонує описувати типізацію аргументів напряму через ці складові, оскільки, кожний з аргументів може мати власну конфігураційну складову, так обʼєкт запиту повинен типізувати рішення тіла запиту, заголовків, динамічних параметрів тощо. Окрім цього запит може включати опис структури сесії, структури відповіді і т.д.

Використання композиції

X-Fiber виділяє окремі документи з можливостями використання в цих спеціалізованих інструментів, наприклад в документі "Репозиторій" наявний провайдер з переліком методів для створення запитів до бази даних. Таке рішення прийняте навмисно, щоб ділити бізнес-логіки на окремі структурні складові, а при описі обробника запита використовувати підхід "Композиція"

handler-execution-process.svg

Аргумент запиту

Обʼєкт запиту складається має наступну структуру, яка відповідно складається з наступного переліку даних:

export type StringObject = Record<string, string>;
export type ModeObject<T = (string | number | boolean)[]> = {
[key in string]:
| T
| string
| string[]
| number
| number[]
| boolean
| boolean[]
| (string | number | boolean)[];
};
export type HttpMethod =
| "GET"
| "POST"
| "PUT"
| "PATCH"
| "DELETE"
| "OPTIONS"
| "HEAD"
| "TRACE";


type FileInfo = {
type: string;
mimetype: string;
encoding: string;
file: Buffer;
fieldName: string;
fileName: string;
};

export type StreamRequest<
PARAMS extends StringObject = any,
HEADERS extends StringObject = any,
QUERIES extends ModeObject = any
> = {
url: string;
path: string;
method: Pick<HttpMethod, 'GET' | 'POST' | 'PUT' | 'DELETE'>
files: Set<string, FileInfo>;
headers: HEADERS;
params: PARAMS;
queries: QUERIES;
};

де:

  • Generic Типи:
    • PARAMS - тип динамічних параметрів запиту
    • HEADERS - тип заголовків запиту.
    • QUERIES - тип query параметрів запиту з включенням можливих типів цих параметрів.
  • Структура обʼєкта запиту:
    • url - повний url шлях.
    • path - деталі url шляху, який не включає host / port та базовий маршрут.
    • method - http метод, який можу бути 'GET', 'POST', 'PUT' або 'DELETE'.
    • files - set колекція з переліком файлів.
    • headers - тип заголовків запиту, який вказується в тип напряму, та дорівнює Generic типу - PARAMS.
    • params - тип динамічних параметрів запиту, який вказується в тип напряму, та дорівнює Generic типу - HEADERS.
    • queries - тип query параметрів запиту, який вказується в тип напряму, та дорівнює Generic типу - QUERIES.

Структура set колекції файлів являє собою слідуючий обʼєкт:

Set(3) {
'c0d4d458-8188-4f93-9718-8adb3eeb4eba' => {
type: 'file',
fieldName: 'Image 1',
fileName: 'IMG_9265.PNG',
encoding: '7bit',
mimetype: 'image/png',
file: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 ... 1929780 more bytes>
},
'eee03961-0ff4-4d6a-bc1d-c203f878c1d2' => {
type: 'file',
fieldName: 'Template',
fileName: 'ClearExtract.mrt',
encoding: '7bit',
mimetype: 'application/octet-stream',
file: <Buffer 7b 0a 20 20 22 52 65 70 6f 72 74 ... 377757 more bytes>
},
'72a99880-2671-4edc-a6f4-0273503a3e9f' => {
type: 'file',
fieldName: 'Extract',
fileName: 'Extract-2000-10-11.pdf',
encoding: '7bit',
mimetype: 'application/pdf',
file: <Buffer 25 50 44 46 2d 31 2e 35 0a 25 e2 ... 238293 more bytes>
}
}

Наприклад описом аргументу SchemaRequest може бути:

import { setStreamer, StreamRequest, Context, Agents, StreamResponse } from 'x-fiber/proton'

type GetOneDynamicParams = {
userId: 'required'
};

type GetOneHeaders = {
'etag': 'required'
}

export const BusUsersAggRouter = setStreamer<'getOne'>({
getOne: {
headers: [
{
name: 'etag',
scope: 'required',
},
],
handler: async (
request: StreamRequest<GetOneDynamicParams, void, GetOneHeaders>,
agents: Agents,
context: Context
): Promise<StreamResponse> => {
// ... route business logic
},
},
});

Аргумент агентів функціональності

Аргумент агентів функціональності являє собою обʼєкт з переліком агентів:

type IFunctionalityAgent = {
// agent functionality description
}

type ISchemaAgent = {
// agent functionality description
}

type IIntegrationAgent = {
// agent functionality description
}

export type Agents = {
fnAgent: IFunctionalityAgent;
schemaAgent: ISchemaAgent;
inAgent: IIntegrationAgent;
};

де:

  • fnAgent - агент з переліком просторів імен функціональності, які надають функціональні компоненти ядра обчислень.
  • schemaAgent - агент з переліком функціональності для доступу до інших складових бізнес-схеми.
  • inAgent - агент з переліком просторів імен функціональності, які надають інтеграційні рішення ядра обчислень.

Деталі структури кожного агента функціональності описується в розділі "Агенти"

Аргумент контексту виконання

інформація

Контекст виконання має базову частину, яка складається зі сховища загальної інформації, унікального ідентифікатора запиту, знімку бізнес-схеми тощо. Окрім базової частини, контекст виконання може містити сесію користувача чи сесію системи, в залежності від типу приватизації. При обробці запиту в рамках життєвого циклу виконання, адаптер http протоколу здійснить валідацію токена доступу, на основі нього здійснить пошук сесії в Redis сховищі та в разі успіху

  • наповнить контекст виконання даними сесії.

Базовий контекст

Структура базового контексту виконання складається з наступним складових:

type BusinessScheme = {
// ... business scheme description
}

type Store = {
service: string,
domain: string,
action: string,
method: string,
ip: string,
requestId: string,
schema: BusinessScheme,
language: string,
request: Request
}

type Context<U extends Record<string,any> = never, S extends Record<string,any> = never> = {
store: Store
// ... other fields
}

де:

  • service - назва сервісу.
  • domain - назва предметної області.
  • action - назва дії.
  • method - http метод.
  • ip - IP джерела взаємодії.
  • requestId - унікальний ідентифікатор запиту.
  • scheme - знімок версії бізнес-схеми.
  • language - мова, якою джерело взаємодії просить надати відповідь.
  • request - повний обʼєкт запиту.

Окрім базового контексту, контекст виконання може бути розширений за рахунок типу приватизації кінцевого маршруту

public:route

Тип приватизації не передбачає перевірок щодо приватності запитів та відсутності перевірки токенів доступу, оскільки вважається, що запити з типом public:route призначені для публічних маршрутів, таких як головні сторінки, опис товарів і т. д.

Результуюча структура контексту виконання

type Store = {
// base store context
}

type Context = {
store: Store
user: undefined,
system: undefined
}

private:user

Тип приватизації передбачає, що запити є конфіденційними і вимагають наявності JWT токену доступу користувача під назвою x-user-access-token. Цей токен надається у двох випадках: під час процедури авторизації при вході в веб-застосунок та при оновленні завдяки x-user-refresh-token.

порада

Для створення авторизації використовуйте вбудовані методи агента fnAgent простору імен sessions, який містить методи для організації роботи з сесіями, включаючи авторизацію. Також використовуйте методи агента fnAgent простору імен scrambler для шифрування, хешування та підтвердження.

Під час обробки запиту з типом приватності private:user, адаптер http ядра обчислень намагатиметься знайти заголовок HTTP з назвою x-user-access-token.

1. Випадок відсутності заголовку

В цьому випадку http адаптер поверне відповідь із http статус кодом 400, що вказує на помилку. Нижче наведено приклад формату цієї відповіді:

{
"type": "FAIL",
data: {
"code": "0002.0001.0007",
"message": "Authorization failed: miss required `x-user-access-token` http header"
}
}

2. Випадок наявності токена зі сплинутим терміном

В цьому випадку http адаптер поверне наступну відповідь з http статус кодом 401:

{
"type": "FAIL",
data: {
"code": "0002.0001.0008",
"message": "Authorization failed: user access token has expired."
}
}

3. Випадок дійсного токену

У випадку, коли заголовок присутній і токен є дійсним, адаптер перевіряє jwt токен на наявність sessionId. Цей sessionId створюється під час авторизації користувача, використовуючи методи з простору імен sessions в веб-застосунку і використовується для отримання інформації про сесію користувача з Redis сховища. Після успішного отримання інформації адаптер додає ці дані до контексту виконання.

type Store = {
// ... base request context
}

type Context<
U extends Record<string,any> = any,
S extends Record<string,any> = any
> = {
store: Store
user: {
sessionId: string // session unique identifier
} & U // other information about the user session
system: S // never
}
примітка

Цей механізм авторизації використовується для доступу до різноманітних ресурсів, пов'язаних з профілем користувача, таких як особисті дані, інформація про ролі, налаштування та інша приватна інформація, необхідна для забезпечення безпеки та відповідності до політик конфіденційності.

private:system

Тип приватизації передбачає, що запити є приватними і вимагають наявності jwt токену доступу до системи - x-system-access-token. Цей токен надається в трьох випадках:

  • При безпосередньому виданні токена, який може бути включений у договір або інші правові документи.
  • Під час авторизації в веб-застосунку через спеціальний маршрут, що описаний в бізнес-схемі.
  • Під час оновлення, за допомогою x-system-refresh-token, який використовується для поновлення токенів.
порада

При авторизації системи через кінцевий маршрут, використовуйте вбудовані методи агента fnAgent простору імен sessions, який містить методи для організації роботи з сесіями, включаючи авторизацію. Також використовуйте методи агента fnAgent простору імен scrambler для шифрування, хешування та підтвердження.

Під час обробки запиту з типом приватності private:system, адаптер http ядра обчислень намагатиметься знайти заголовок HTTP з назвою x-system-access-token.

1. Випадок відсутності заголовку

В цьому випадку http адаптер поверне відповідь із http статус кодом 400, що вказує на помилку. Нижче наведено приклад формату цієї відповіді:

{
"type": "FAIL",
data: {
"code": "0002.0001.0007",
"message": "Authorization failed: miss required `x-system-access-token` http header"
}
}

2. Випадок наявності токена зі сплинутим терміном

В цьому випадку http адаптер поверне наступну відповідь з http статус кодом 401:

{
"type": "FAIL",
data: {
"code": "0002.0001.0008",
"message": "Authorization failed: system access token has expired."
}
}

3. Випадок дійсного токену

У випадку, коли заголовок присутній і токен є дійсним, адаптер перевіряє jwt токен на наявність sessionId. Цей sessionId створюється під час авторизації системи, використовуючи методи з простору імен sessions в веб-застосунку або через пряму передачу токена доступу і використовується для отримання інформації про сесію системи з Redis сховища. Після успішного отримання інформації адаптер додає ці дані до контексту виконання.

type Store = {
// ... base request context
}

type Context<
U extends Record<string,any> = any,
S extends Record<string,any> = any
> = {
store: Store
user: U
system: {
sessionId: string // session unique identifier
} & S // other information about the system session
}
примітка

Зазначений тип приватизації є ключовим у забезпеченні безпеки та конфіденційності при доступі до ресурсів на маршрутах інтеграцій та побудові міжсистемної взаємодії.

Відповідь

Обробник запиту, за потреби, може формувати відповідь для відправки на запит. X-Fiber впроваджує варіанти відповіді.

type ResponseFormat = 'json' | 'file' | 'redirect' | 'status';
type JsonFormatType = 'ok' | 'error' | 'exception' | 'validation';
type StringObject = Record<string, string>

interface BaseResponse<HEADERS extends StringObject = any> {
format: ResponseFormat;
headers?: HEADERS;
statusCode?: number;
}

interface JsonResponse<BODY = any, HEADERS extends StringObject = any>
extends BaseResponse<HEADERS> {
format: "json";
type: JsonFormatType;
data: BODY;
}

interface FileResponse<HEADERS extends StringObject = any>
extends BaseResponse<HEADERS> {
format: "file";
type: JsonFormatType;
files: unknown
}

interface RedirectResponse<HEADERS extends StringObject = any>
extends BaseResponse<HEADERS> {
url: string;
}

export type Response<BODY = never, HEADERS extends StringObject = never> =
| BaseResponse<HEADERS>
| JsonResponse<BODY, HEADERS>
| FileResponse<HEADERS>
| RedirectResponse<HEADERS>;

де:

  • ResponseFormat - тип відповіді.
  • JsonFormatType - типи структури відповіді при json форматі відповіді.
  • StringObject - обʼєкт, який може налічувати лише строкові ключі та строкові значення.
  • BaseResponse - базова відповідь на запит.
  • JsonResponse - json відповідь на запит.
  • FileResponse - відповідь з файлами на запит.
  • RedirectResponse - відповідь на запит з використання пересилання redirect.
  • Response - можливі типи відповіді.

Відсутність відповіді

В разі відсутності відповіді, в обробнику запиту, X-Fiber надасть у відповідь пусту відповідь зі статусом 204 No Content.

Обробка виключень в обробниках запиту

X-Fiber поділяє виключення на простори відповідальності, так, відповідне виключення генерується відповідним провайдером виключень, наприклад генерація виключень в бізнес-схемі оброблюється провайдером виключень бізнес-схеми, для обробки запитів до БД ядро обчислень використовує власний обробник виключень помилок вв БД. В залежності від провайдера, який буде обробляти помилку буде наданий різних тип відповіді. Наприклад тип відповіді при виключеннях, які генеруються в бізнес-схемі

{
type: "fail",
code: "XYZ.0001",
message: 'File not found'
}

де:

  • тип виключення, за замовчуванням fail,
  • код помилки, за замовчуванням не включається в відповідь, але доступний для передачі типу при формуванні виключення. Рекомендується використовувати коди помилок, для коректної обробки помилок в джерелах взаємодії, оскільки текст помилки може бути змінений в залежності від локалізації.
  • повідомлення - визначає опис виключення.

Життєвий цикл виконання

Кожний обробник запиту виконується в рамках життєвого циклу виконання запиту:

route-lifecycle.svg s 1. Перевірка CORS Механізм CORS доступний для використання. Додатковий опис може бути наданий при описі конкретного сервісу.

2. Перевірка структури маршруту Валідація елементів маршруту, включаючи побудову об'єкта динамічних параметрів, перевірку наявності обов'язкових заголовків. Також проводиться перевірка структури параметрів запиту. У випадку відсутності обов'язкових елементів, http адаптер` ядра обчислень сформує надасть відповідь з помилкою валідації.

3. Перевірка елементів маршруту Перевірка валідності елементів маршруту. Пошук відповідного сервісу, прикладної області та маршруту з http запитом. У випадку відсутності обов'язкових елементів, http адаптер` ядра обчислень сформує надасть відповідь з помилкою валідації.

4. Перевірка підтримуваної мови

Виконується перевірка підтримуваної мови для обробки запиту з відповідною мовою. При налаштуванні конфігурації веб-застосунку потрібно вказати список підтримуваних мов, які будуть використовуватися для перевірки.

5. Перевірка типу приватизації AuthScope

Простору авторизації AuthScope визначає доступність ресурсу для користувачів та систем на основі типу приватизації кінцевого маршруту.

6. Формування контексту

Формування контексту запиту для послідуючої передачі контексту виконання в обробник запиту.

7. Запуск виконання контексту запиту

Створює новий контекст для зберігання даних у AsyncLocalStorage для забезпечення ізоляції даних між різними запитами або операціями, що теоретично можуть відбуватись паралельно, з привʼязуванням до унікального ідентифікатора запиту.

8. Виконання запиту бізнес-схеми

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

9. Формування відповіді

В залежності від типу результату відбувається формування відповіді на запит.

11. Закриття контексту виконання запиту

Закриття контексту виконання запиту, логування відповіді, статус тощо.

Реалізація маршруту

import { setStreamer } from '@x-fiber/proton';

export const BusUsersAggStreamer = setStreamer<'getOne'>({
getOne: {
version: 'v1',
scope: "public:route",
handler: async (request, agents, context) => {
const names: string[] = []

for (const [_, file] of request.files) {
names.push(file.fileName);
}

return {
format: "json",
type: "ok",
data: { names },
};
}
}
})

Реєстрація

Щоб успішно використовувати кінцеві маршрути, документ "Маршрутизатор" повинен бути зареєстрований в документі "Реєстр" цієї предметної області. Наприклад для предметної області - агрегат "Користувачі", необхідно в опис документів функції setRegistry для встановлення посилання на маршрутизатор та інші компоненти модуля:

import { setRegistry } from '@x-fiber/proton';
import { BusUsersAggStreamer } from './BusUsers.agg.streamer';

export const BusUsersAggRegistry = setRegistry<'BusUsersAgg'>('BusUsersAgg', {
streamer: BusUsersAggStreamer,
// ... other documents
});

Власні рішення

warning

X-Fiber виконує обробники запитів в рамках їх життєвого циклу, це означає, що інструменти, які не надає X-Fiber, але необхідні для реалізації бізнес-логіки є можливість поділити на два типи:

  • інструменти без створення стану - використання таких інструментів, наприклад date-fns, як бібліотека для роботи з датами, можуть бути додані в будь-якому місці попередньо встановивши їх в проєкт. X-Fiber рекомендує опис розгортання таких інструментів виносити в окрему директорію від опису бізнес-логіки.
  • інструменти зі створення стану - використання таких практик наразі X-Fiber не покривається, але рішення яке буде реалізовано в найближчих релізах це окрема дві функції - запуску та старту, які будуть запускатись після запуску та зупинки життєвого циклу роботи ядра обчислень. Ця функція може приймати ваші рішення по запуску та зупинки використання стану інструментів.

У разі впровадження власних рішень, рекомендується керуватися кращими практиками з метою поліпшення підтримки кодової бази. Якщо ви вважаєте, що інструмент, який ви використовуєте, має достатню популярність, ви можете запропонувати його включення в саму платформу X-Fiber. Ми готові обговорити цю можливість з вами, а при позитивному рішенні ми включимо цей інструмент до архітектури платформи.