[JavaScript, API, TypeScript] TypedAPI: клиент-сервер для TypeScript
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Предлагаю вашему вниманию TypedAPI: библиотеку API клиента-сервера для проектов, в которых фронт и бэк написаны на TypeScript. Акцент делается на максимальной простоте использования. Суть такая: вы пишете API как обычный TypeScript класс с некоторыми ограничениями, потом автоматом из класса строится интерфейс, которым будет пользоваться клиентское приложение. Также генерируется некоторая служебная информация. Остается только настроить коннекторы (доступны HTTP и WebSocket). Валидацию, хранение подключений, и др. берет на себя TypedAPI. Есть поддержка событий.
Чтобы поиграться, есть два простеньких демонстрационных приложения: Hello, world! и Демо-чат.
Установка
TypedAPI состоит из нескольких библиотек, которые подключаются в зависимости от типа использования.
- typedapi-core: ядро, подключается клиентом и сервером
- typedapi-server: ядро сервера, подключается на сервере, включает в себя функционал HTTP сервера
- typedapi-client: ядро клиента, подключается на клиенте
- typedapi-server-ws — WebSocket сервер
- typedapi-client-browser-http — HTTP клиент
- typedapi-client-browser-ws — WebSocket клиент
- typedapi-parser — Парсер для API класса и создания интерфейса. Подключается на сервере с флагом --dev
- typedapi-redis-signaling — для проксирования событий из микросервисов во входной API
Пример, если мы хотим использовать WebSocket соединение:
# на сервере
npm install --save typedapi-core typedapi-server typedapi-server-ws
npm install --save-dev typedapi-parser
# на клиенте
npm install --save typedapi-core typedapi-client typedapi-client-browser-ws
Для HTTP соединения:
# for server
npm install --save typedapi-core typedapi-server
npm install --save-dev typedapi-parser
# for client
npm install --save typedapi-core typedapi-client typedapi-client-browser-http
Требования к API классу
- Все методы должны возвращать Promise
- Есть ограничения по типу данных, которые могут принимать и возвращать методы (см. ниже)
- Класс может содержать дочерние свойства-объекты, построеные по тем же правилам
Дополнительно класс может содержать свойства типа Event и ParametricEvent для реализации событий, и есть заранее определенные инъекции для авторизации и хранения базовой информации о пользователе (см. ниже).
Пример класса для «Hello, world!»:
export class Api {
async hello(name: string): Promise<string> {
return `Hello, ${name}!`
}
}
Ограничения по типам данных
Методы могут возвращать/принимать следующие типы данных:
- Скалярные: number, string, boolean, Date, undefined, null
- Array, Tuple, Enum, Union. Могут содержать только описанные здесь типы.
- Объекты-структуры без методов
- Индексированные объекты типа { [key: string | number]: SomeOtherType }
Прием/передача any, unknown запрещена.
Генерация интерфейса
Генерация интерфейса производится путем использования команды typedapi-parse из пакета typedapi-parser:
typedapi-parse [sourceFilename] [sourceObjectName] [outFilename] [reflectionOutFileName]
где:
- sourceFilename: Путь к файлу, где хранится ваш API
- sourceObjectName: Название класса в этом файле
- outFilename: Путь к файлу, в который будет записан интерфейс для клиента
- reflectionOutFileName: Путь к файлу, который будет хранить reflections для всех методов и данных. Он используется на сервере для валидации данных
Создание соединения
После того, как вы настроили API и сегенерировали интерфейсы, можно настраивать соединение. Пример как это может выглядеть для WebSocket:
Сервер
import { WebSocketServer } from "typedapi-server-ws"
import { buildMap } from "typedapi-server"
// файл, сгенерированный командой typedapi-parse для сервера
import { reflection } from "./apiReflection"
// Ваш API класс
import { Api } from "./Api"
new WebSocketServer({
apiMap: buildMap(reflection, new Api),
port: 8090
})
Клиент
import { WebSocketTransport } from "typedapi-client-browser-ws"
// файл, сгенерированный командой typedapi-parse для клиента
import { createClient } from "./apiReflection"
const api = createClient({ transport })
// теперь можно вызывать методы API
let result = await api.hello(name)
Настройка HTTP соединения происходит аналогичным способом, можно посмотреть в документации.
События
TypedAPI поддерживает события. При WebSocket соединении оповещение происходит обычным образом, отправкой данных через сокет. При HTTP соединении используется HTTP polling.
Пример cоздания события на сервере:
import { Event } from "typedapi-server"
export class Api {
someEvent = new Event<string>()
}
// отправляем событие всем продписчикам
api.someEvent.fire(data)
// отправляем событие одному пользователю
api.someEvent.fireForUser(data, userId)
// Отправляем группе пользователей
api.someEvent.fireForGroup(data, groupName)
// отправляем конкретной сессии
api.someEvent.fireForSession(data, sessionId)
// Отправялем конкретному соединению
api.someEvent.fireForConnection(data, connectionId)
Обработка на клиенте:
// Подписываемся на событие
const subscription = await api.someEvent.subscribe(data => {
// обработка события
})
// Отписка
await subscription.unsubscribe()
Параметрические события
Параметрические события это события, в которых у подписки могут быть определенные параметры, которые определяют, нужно ли оповещать пользователя о конкретном событии.
Более подробно про параметрические события можно прочитать в документации.
Авторизация
Для того, чтобы реализовать авторизацию в вашем API, надо:
- Реализовать SessionProviderInterface и передать его в конструктор сервиса. По умолчанию используется MemorySessionProvider, который будет сбрасываться при каждой перезагрузке сервера.
- Реализовать методы, которые возвращают AuthDataResponse. Это специальный ответ метода, который обрабатывается по другому, нежели другие ответы.
Интерфейс AuthDataResponse выглядит так:
type AuthDataResponse = {
newAuthData: {
id?: string | number
groups?: string[]
name?: string
email?: string
phone?: string
}
// ответ, который будет отправлен пользователю
// newAuthData используется только для внутренних нужд
response: boolean
}
пример реализации API с авторизацией:
import { AuthDataResponse } from "typedapi-server"
export class ClientApi {
/**
* Проверяем логин и пароль, если подходит авторизуем
**/
async login(username: string, password: string): Promise<AuthDataResponse> {
let user = await usersRepository.login(username, password)
if(!user) {
return {
response: false,
newAuthData: {}
}
} else {
return {
response: true,
newAuthData: {
id: user.id,
groups: user.groups
}
}
}
}
/**
* Logout
**/
async logout(): Promise<AuthDataResponse> {
return {
response: true,
newAuthData: {}
}
}
/**
* в apiUserID будет автоматически добавлен идентификатор пользователя.
* Если пользватель не авторизован, он получит NotAuthorizedError
**/
async getUserData(apiUserId: number): Promise<SomeUserData> {
let userData = await usersRespotory.getUserData(apiUserId)
return userData
}
}
Также помимо apiUserId можно получать и другие данные о пользователе, подробнее в документации.
Микросервисы
Для разбиения API на микросервисы используется следующая идея: на каждом микросервисе поднимается экземпляр API, и с помощью для каждого экземпляра устанавливается, какой сервис будет отвественен за обработку определенных методов. Для этого есть следующие инструменты:
- HttpProxyClient —
Это объект проксирует вызовы методов со входного API на внутренний сервис
- HttpTrustServer —
Этот объект принимает вызов от HttpProxyClient и вызывает запрашиваемый метод
- RedisPublisher —
Присоединяется к API, слушает события, и перенаправляет их в Redis. Используется во внутренних сервисах.
- RedisSubscriber —
Слушает события из Редиса, и запускает их на входном API
Архитектура может выглядеть примерно так:
Примеры кода можно найти в документации.
Заключение
Я описал ключевые особенности TypedAPI, для дополнительной информации можно почитать документацию. Я уже использую эту библиотеку в паре своих проектов, но пока она все же находится в режиме беты. Я активно ее развиваю, и надеюсь, что она будет полезна людям. Буду рад любой конструктивной критике.
Спасибо за внимание.
===========
Источник:
habr.com
===========
Похожие новости:
- [Разработка веб-сайтов, CSS, Программирование, Java] От студента до учителя: как разобраться в веб-разработке, если это не твой профиль
- [PHP, API, CRM-системы] Заметки по API Aliexpress. Экспорт заказов в Bitrix24, RetailCRM, amoCRM
- [C++, Реверс-инжиниринг, Игры и игровые приставки, Лайфхаки для гиков] Как в Runescape ловят пользователей ботов, и почему они не поймали меня (перевод)
- [JavaScript, TypeScript] Пишем юнит тесты на TypeScript'е (на примере котиков)
- [Разработка веб-сайтов, JavaScript, Конференции, Микросервисы] Frontend Meetup 20/04
- [Программирование, ReactJS, Управление разработкой, TypeScript] Wrike переходит с Dart на новый стек. Какой?
- [IT-инфраструктура, API, Облачные сервисы, Kubernetes] Масштабирование Kubernetes в Pinterest: через сбои и аварии (перевод)
- [JavaScript, Node.JS, TypeScript] FSTB – работа с файлами в Node.js без боли
- [JavaScript, Google API, GitHub] Google Sheets — как разноплановый помощник для непростых задач или как я делал анализатор футбольный матчей
- [Разработка веб-сайтов, JavaScript, Совершенный код, Google Chrome] Почему консоль разработчика Chrome иногда лжет (перевод)
Теги для поиска: #_javascript, #_api, #_typescript, #_typescript, #_api, #_clientserver, #_javascript, #_api, #_typescript
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:38
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Предлагаю вашему вниманию TypedAPI: библиотеку API клиента-сервера для проектов, в которых фронт и бэк написаны на TypeScript. Акцент делается на максимальной простоте использования. Суть такая: вы пишете API как обычный TypeScript класс с некоторыми ограничениями, потом автоматом из класса строится интерфейс, которым будет пользоваться клиентское приложение. Также генерируется некоторая служебная информация. Остается только настроить коннекторы (доступны HTTP и WebSocket). Валидацию, хранение подключений, и др. берет на себя TypedAPI. Есть поддержка событий. Чтобы поиграться, есть два простеньких демонстрационных приложения: Hello, world! и Демо-чат. Установка TypedAPI состоит из нескольких библиотек, которые подключаются в зависимости от типа использования.
Пример, если мы хотим использовать WebSocket соединение: # на сервере
npm install --save typedapi-core typedapi-server typedapi-server-ws npm install --save-dev typedapi-parser # на клиенте npm install --save typedapi-core typedapi-client typedapi-client-browser-ws Для HTTP соединения: # for server
npm install --save typedapi-core typedapi-server npm install --save-dev typedapi-parser # for client npm install --save typedapi-core typedapi-client typedapi-client-browser-http Требования к API классу
Дополнительно класс может содержать свойства типа Event и ParametricEvent для реализации событий, и есть заранее определенные инъекции для авторизации и хранения базовой информации о пользователе (см. ниже). Пример класса для «Hello, world!»: export class Api {
async hello(name: string): Promise<string> { return `Hello, ${name}!` } } Ограничения по типам данных Методы могут возвращать/принимать следующие типы данных:
Прием/передача any, unknown запрещена. Генерация интерфейса Генерация интерфейса производится путем использования команды typedapi-parse из пакета typedapi-parser: typedapi-parse [sourceFilename] [sourceObjectName] [outFilename] [reflectionOutFileName]
где:
Создание соединения После того, как вы настроили API и сегенерировали интерфейсы, можно настраивать соединение. Пример как это может выглядеть для WebSocket: Сервер import { WebSocketServer } from "typedapi-server-ws"
import { buildMap } from "typedapi-server" // файл, сгенерированный командой typedapi-parse для сервера import { reflection } from "./apiReflection" // Ваш API класс import { Api } from "./Api" new WebSocketServer({ apiMap: buildMap(reflection, new Api), port: 8090 }) Клиент import { WebSocketTransport } from "typedapi-client-browser-ws"
// файл, сгенерированный командой typedapi-parse для клиента import { createClient } from "./apiReflection" const api = createClient({ transport }) // теперь можно вызывать методы API let result = await api.hello(name) Настройка HTTP соединения происходит аналогичным способом, можно посмотреть в документации. События TypedAPI поддерживает события. При WebSocket соединении оповещение происходит обычным образом, отправкой данных через сокет. При HTTP соединении используется HTTP polling. Пример cоздания события на сервере: import { Event } from "typedapi-server"
export class Api { someEvent = new Event<string>() } // отправляем событие всем продписчикам api.someEvent.fire(data) // отправляем событие одному пользователю api.someEvent.fireForUser(data, userId) // Отправляем группе пользователей api.someEvent.fireForGroup(data, groupName) // отправляем конкретной сессии api.someEvent.fireForSession(data, sessionId) // Отправялем конкретному соединению api.someEvent.fireForConnection(data, connectionId) Обработка на клиенте: // Подписываемся на событие
const subscription = await api.someEvent.subscribe(data => { // обработка события }) // Отписка await subscription.unsubscribe() Параметрические события Параметрические события это события, в которых у подписки могут быть определенные параметры, которые определяют, нужно ли оповещать пользователя о конкретном событии. Более подробно про параметрические события можно прочитать в документации. Авторизация Для того, чтобы реализовать авторизацию в вашем API, надо:
Интерфейс AuthDataResponse выглядит так: type AuthDataResponse = {
newAuthData: { id?: string | number groups?: string[] name?: string email?: string phone?: string } // ответ, который будет отправлен пользователю // newAuthData используется только для внутренних нужд response: boolean } пример реализации API с авторизацией: import { AuthDataResponse } from "typedapi-server"
export class ClientApi { /** * Проверяем логин и пароль, если подходит авторизуем **/ async login(username: string, password: string): Promise<AuthDataResponse> { let user = await usersRepository.login(username, password) if(!user) { return { response: false, newAuthData: {} } } else { return { response: true, newAuthData: { id: user.id, groups: user.groups } } } } /** * Logout **/ async logout(): Promise<AuthDataResponse> { return { response: true, newAuthData: {} } } /** * в apiUserID будет автоматически добавлен идентификатор пользователя. * Если пользватель не авторизован, он получит NotAuthorizedError **/ async getUserData(apiUserId: number): Promise<SomeUserData> { let userData = await usersRespotory.getUserData(apiUserId) return userData } } Также помимо apiUserId можно получать и другие данные о пользователе, подробнее в документации. Микросервисы Для разбиения API на микросервисы используется следующая идея: на каждом микросервисе поднимается экземпляр API, и с помощью для каждого экземпляра устанавливается, какой сервис будет отвественен за обработку определенных методов. Для этого есть следующие инструменты:
Архитектура может выглядеть примерно так: Примеры кода можно найти в документации. Заключение Я описал ключевые особенности TypedAPI, для дополнительной информации можно почитать документацию. Я уже использую эту библиотеку в паре своих проектов, но пока она все же находится в режиме беты. Я активно ее развиваю, и надеюсь, что она будет полезна людям. Буду рад любой конструктивной критике. Спасибо за внимание. =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:38
Часовой пояс: UTC + 5