расширить существующий API с помощью пользовательских конечных точек

12

Я создаю API для нескольких клиентов. Подобные основные конечные точки /usersиспользуются каждым клиентом, но некоторые конечные точки зависят от индивидуальных настроек. Таким образом, может случиться так, что пользователь А хочет иметь специальную конечную точку, /groupsи никакой другой клиент не будет иметь эту функцию. Так же, как sidenote , каждый клиент также использовал бы свою собственную схему базы данных из-за этих дополнительных функций.

Я лично использую NestJs (экспресс под капотом). Таким образом, в app.moduleнастоящее время регистрируются все мои основные модули (со своими конечными точками и т. Д.)

import { Module } from '@nestjs/common';

import { UsersModule } from './users/users.module'; // core module

@Module({
  imports: [UsersModule]
})
export class AppModule {}

Я думаю, что эта проблема не связана с NestJ, так как бы вы справились с этим в теории?

Мне в основном нужна инфраструктура, способная обеспечить базовую систему. Больше нет конечных точек ядра, потому что каждое расширение уникально, и возможны множественные /usersреализации. При разработке новой функции основное приложение не должно касаться. Расширения должны интегрироваться сами или интегрироваться при запуске. Базовая система поставляется без конечных точек, но будет расширена из этих внешних файлов.

Некоторые идеи приходят мне в голову


Первый подход:

Каждое расширение представляет новый репозиторий. Определите путь к пользовательской внешней папке, содержащей все проекты расширений. Этот пользовательский каталог будет содержать папку groupsсgroups.module

import { Module } from '@nestjs/common';

import { GroupsController } from './groups.controller';

@Module({
  controllers: [GroupsController],
})
export class GroupsModule {}

Мой API мог бы пройти через этот каталог и попытаться импортировать каждый файл модуля.

  • плюсы:

    1. Пользовательский код хранится вдали от основного хранилища.
  • минусы:

    1. NestJs использует Typescript, поэтому я должен сначала скомпилировать код. Как бы я управлял сборкой API и сборками из пользовательских приложений? (Подключи и играй система)

    2. Пользовательские расширения очень свободны, потому что они просто содержат некоторые машинописные файлы. Из-за того, что они не имеют доступа к каталогу API node_modules, мой редактор покажет мне ошибки, потому что он не может разрешить внешние зависимости пакета.

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


Второй подход. Храните каждое расширение в подпапке папки src API. Но добавьте эту подпапку в файл .gitignore. Теперь вы можете хранить свои расширения внутри API.

  • плюсы:

    1. Ваш редактор может разрешить зависимости

    2. Перед развертыванием вашего кода вы можете запустить команду сборки и будет иметь один дистрибутив

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

  • минусы:

    1. При разработке вы должны скопировать файлы репозитория в эту подпапку. После изменения чего-либо вы должны скопировать эти файлы обратно и переопределить файлы репозитория обновленными.

Третий подход:

Внутри внешней пользовательской папки все расширения являются полноценными автономными API. Ваш основной API просто обеспечит аутентификацию и может выступать в качестве прокси для перенаправления входящих запросов в целевой API.

  • плюсы:

    1. Новые расширения могут быть легко разработаны и протестированы
  • минусы:

    1. Развертывание будет сложно. У вас будет основной API и n расширений API, запускающих собственный процесс и прослушивающих порт.

    2. Система прокси может быть хитрой. Если клиент запрашивает, /usersпрокси-сервер должен знать, какое расширение API прослушивает эту конечную точку, вызывает этот API и пересылает этот ответ обратно клиенту.

    3. Чтобы защитить API расширений (аутентификация обрабатывается основным API), прокси должен делиться секретом с этими API. Таким образом, API расширения будет передавать входящие запросы, только если соответствующий секретный ключ предоставлен прокси-сервером.


Четвертый подход:

Микросервисы могут помочь. Я взял руководство отсюда https://docs.nestjs.com/microservices/basics

Я мог бы иметь микросервис для управления пользователями, управления группами и т. Д. И использовать эти сервисы, создав небольшой API / шлюз / прокси, который вызывает эти микросервисы.

  • плюсы:

    1. Новые расширения могут быть легко разработаны и протестированы

    2. Отдельные проблемы

  • минусы:

    1. Развертывание будет сложно. У вас будет основной API и n микросервисов, запускающих собственный процесс и прослушивающих порт.

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

    3. Чтобы защитить API расширений (аутентификация обрабатывается основным API), прокси должен делиться секретом с этими API. Таким образом, API расширения будет передавать входящие запросы, только если соответствующий секретный ключ предоставлен прокси-сервером.

hrp8sfH4xQ4
источник
2
это может помочь github.com/nestjs/nest/issues/3277
Question3r
Спасибо за ссылку. Но я не думаю, что у меня должны быть пользовательские расширения в моем коде. Я проверю, решат ли микросервисы проблему docs.nestjs.com/microservices/basics
hrp8sfH4xQ4
Я думаю, что ваша проблема связана с авторизацией, а не отдыхом.
adnanmuttaleb
@ adnanmuttaleb Не могли бы вы объяснить, почему =?
hrp8sfH4xQ4

Ответы:

6

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

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

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

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

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

Узнайте больше о частных пакетах здесь: Private Packages NPM

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

Способы иметь ваш личный реестр npm

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

Я написал простую справочную реализацию для такой системы:

Фреймворк: локомоция, сервис локатор

Пример плагина для проверки палиндромов: пример плагина locomotion

Приложение, использующее инфраструктуру для поиска плагинов: пример приложения locomotion

Вы можете играть с этим, загрузив ее с НПМ помощью npm install -s locomotionвам нужно будет указать plugins.jsonфайл со следующей схемой:

{
    "path": "relative path where plugins should be stored",
    "plugins": [
        { 
           "module":"name of service", 
           "dir":"location within plugin folder",
           "source":"link to git repository"
        }
    ]
}

пример:

{
    "path": "./plugins",
    "plugins": [
        {
            "module": "palindrome",
            "dir": "locomotion-plugin-example",
            "source": "https://github.com/drcircuit/locomotion-plugin-example.git"
        }
    ]
}

загрузить его так: const loco = require ("locomotion");

Затем он возвращает обещание, которое разрешит объект локатора службы, который имеет метод локатора, чтобы получить ваши службы:

loco.then((svc) => {
    let pal = svc.locate("palindrome"); //get the palindrome service
    if (pal) {
        console.log("Is: no X in Nixon! a palindrome? ", (pal.isPalindrome("no X in Nixon!")) ? "Yes" : "no"); // test if it works :)
    }
}).catch((err) => {
    console.error(err);
});

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

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

Эспен
источник
Спасибо. Возникают две проблемы, кажется, что мы полагаемся на npm, и нам приходится настраивать собственный реестр. Во-вторых, приватный npm больше не является бесплатным. Я надеялся найти базовое техническое решение. Но +1 за идею :)
hrp8sfH4xQ4
1
добавлена ​​эталонная реализация элементарного решения для системы такого типа.
Espen
3

Я бы пошел на внешний вариант пакетов.

Вы можете структурировать свое приложение, чтобы иметь packagesпапку. Я хотел бы иметь скомпилированные сборки UMD внешних пакетов в этой папке, чтобы у вашей скомпилированной машинописи не было проблем с пакетами. Все пакеты должны иметь index.jsфайл в корневой папке каждого пакета.

И ваше приложение может запустить цикл через пакеты папок с использованием fsи requireвсех пакетов index.jsв ваше приложение.

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

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

Калеш Каладхаран
источник
Спасибо за ответ. Я думаю, что это звучит как решение @ Espen уже опубликовано, нет?
hrp8sfH4xQ4
@ hrp8sfH4xQ4 Да, в продолжение. Я добавил его после прочтения вашего комментария о нежелании использовать npm. Выше это решение, которое вы можете сделать, чтобы избежать частной учетной записи npm. Более того, я считаю, что вам не нужно добавлять пакеты, созданные кем-то за пределами вашей организации. Правильно?
Калеш Каладхарен
Кстати. но было бы здорово поддержать это тоже ... каким-то образом ...
hrp8sfH4xQ4
Если вам нужна опция для добавления сторонних пакетов, то npmесть способ сделать это или любой другой менеджер пакетов. В таких случаях моего решения будет недостаточно.
Калеш Каладхарен
Если вы не возражаете, я бы хотел подождать, чтобы собрать как можно больше подходов
hrp8sfH4xQ4