Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP API versioning #2660

Merged
merged 23 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e2dc810
Reworked HTTP API router to support multiple API versions, made json-…
u-hubar Aug 9, 2023
40c324f
Fixed wrong controller name
u-hubar Aug 9, 2023
108922a
Moved API version related functions to the separate service, added us…
u-hubar Aug 14, 2023
b2cfd36
Renamed old HTTP API version to v0, mounted /* routes to /v0/*, mount…
u-hubar Aug 16, 2023
2273369
Added missing schema args to the HTTP API routes config
u-hubar Aug 16, 2023
12ff02e
Changed HTTP API Routes config description
u-hubar Aug 16, 2023
9de28fa
Removed redundant function
u-hubar Aug 16, 2023
3f6b496
Shortened HTTP API Routes config, reworked generic listeners initiali…
u-hubar Aug 16, 2023
fa23f68
Removed redundant schema definition in the HTTP API Routes config
u-hubar Aug 17, 2023
8109586
Variable naming fix
u-hubar Aug 17, 2023
181ce0f
Removed redundant module from http api router
u-hubar Aug 17, 2023
1b3a21c
Merge branch 'v6/develop' into v6/api-versioning
u-hubar Aug 17, 2023
6338efd
Removed redundant module from http client module manager
u-hubar Aug 17, 2023
03370f1
Added new Postman API collection
u-hubar Aug 17, 2023
132bb01
Merge branch 'v6/develop' into improvement/postman-collection
zeroxbt Aug 18, 2023
9c2c608
Merge branch 'v6/develop' into v6/api-versioning
zeroxbt Aug 18, 2023
2336220
Added HTTP API Router unit test
u-hubar Aug 18, 2023
2362520
Removed redundant function mocks from httpClientModuleManagerMock
u-hubar Aug 18, 2023
b66114d
Added OpenAPI collection
u-hubar Aug 18, 2023
9cd910a
Merge pull request #2673 from OriginTrail/improvement/postman-collection
u-hubar Aug 23, 2023
070a529
Removed test v1/info route, bumped version to 6.0.14
u-hubar Aug 24, 2023
c3f88a8
Resolved conflict with the node version
u-hubar Aug 24, 2023
ed1c5e9
Removed v1/info route from the API config
u-hubar Aug 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions src/constants/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,62 @@ export const ARCHIVE_UPDATE_RESPONSES_FOLDER = 'update_responses';
*/
export const COMMAND_QUEUE_PARALLELISM = 100;

/**
* @constant {object} HTTP_API_ROUTES -
* HTTP API Routes with parameters
*/
export const HTTP_API_ROUTES = {
v0: {
publish: {
method: 'post',
path: '/publish',
options: { rateLimit: true },
},
update: {
method: 'post',
path: '/update',
options: { rateLimit: true },
},
query: {
method: 'post',
path: '/query',
options: {},
u-hubar marked this conversation as resolved.
Show resolved Hide resolved
},
'local-store': {
method: 'post',
path: '/local-store',
options: {},
},
get: {
method: 'post',
path: '/get',
options: { rateLimit: true },
},
result: {
method: 'get',
path: '/:operation/:operationId',
options: {},
},
info: {
method: 'get',
path: '/info',
options: {},
},
'bid-suggestion': {
method: 'get',
path: '/bid-suggestion',
options: {},
},
},
v1: {
info: {
method: 'get',
path: '/info',
options: {},
},
},
};

/**
* @constant {object} NETWORK_PROTOCOLS -
* Network protocols
Expand Down
1 change: 1 addition & 0 deletions src/controllers/http-api/base-http-api-controller.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
class BaseController {
constructor(ctx) {
this.config = ctx.config;
this.logger = ctx.logger;
}

Expand Down
134 changes: 67 additions & 67 deletions src/controllers/http-api/http-api-router.js
Original file line number Diff line number Diff line change
@@ -1,89 +1,89 @@
import stringUtil from '../../service/util/string-util.js';
import { HTTP_API_ROUTES } from '../../constants/constants.js';

class HttpApiRouter {
constructor(ctx) {
this.config = ctx.config;
this.httpClientModuleManager = ctx.httpClientModuleManager;

this.getHttpApiController = ctx.getHttpApiController;
this.publishHttpApiController = ctx.publishHttpApiController;
this.updateHttpApiController = ctx.updateHttpApiController;
this.localStoreHttpApiController = ctx.localStoreHttpApiController;
this.queryHttpApiController = ctx.queryHttpApiController;
this.resultHttpApiController = ctx.resultHttpApiController;
this.infoHttpApiController = ctx.infoHttpApiController;
this.bidSuggestionHttpApiController = ctx.bidSuggestionHttpApiController;
this.apiRoutes = HTTP_API_ROUTES;
this.apiVersions = Object.keys(this.apiRoutes);

this.routers = {};
for (const version of this.apiVersions) {
this.routers[version] = this.httpClientModuleManager.createRouterInstance();

const operations = Object.keys(this.apiRoutes[version]);

for (const operation of operations) {
const versionedController = `${stringUtil.toCamelCase(
operation,
)}HttpApiController${stringUtil.capitalize(version)}`;
this[versionedController] = ctx[versionedController];
}
}
this.routers.latest = this.httpClientModuleManager.createRouterInstance();

this.jsonSchemaService = ctx.jsonSchemaService;
}

async initialize() {
this.initializeBeforeMiddlewares();
this.initializeListeners();
await this.initializeVersionedListeners();
this.initializeRouters();
this.initializeAfterMiddlewares();
await this.httpClientModuleManager.listen();
}

initializeListeners() {
this.httpClientModuleManager.post(
'/publish',
(req, res) => {
this.publishHttpApiController.handlePublishRequest(req, res);
},
{ rateLimit: true, requestSchema: this.jsonSchemaService.publishSchema() },
);

this.httpClientModuleManager.post(
'/update',
(req, res) => {
this.updateHttpApiController.handleUpdateRequest(req, res);
},
{ rateLimit: true, requestSchema: this.jsonSchemaService.updateSchema() },
);

this.httpClientModuleManager.post(
'/query',
(req, res) => {
this.queryHttpApiController.handleQueryRequest(req, res);
},
{ requestSchema: this.jsonSchemaService.querySchema() },
);

this.httpClientModuleManager.post(
'/local-store',
(req, res) => {
this.localStoreHttpApiController.handleLocalStoreRequest(req, res);
},
{ requestSchema: this.jsonSchemaService.localStoreSchema() },
);

this.httpClientModuleManager.post(
'/get',
(req, res) => {
this.getHttpApiController.handleGetRequest(req, res);
},
{ rateLimit: true, requestSchema: this.jsonSchemaService.getSchema() },
);

this.httpClientModuleManager.get('/:operation/:operationId', (req, res) => {
this.resultHttpApiController.handleOperationResultRequest(req, res);
});

this.httpClientModuleManager.get('/info', (req, res) => {
this.infoHttpApiController.handleInfoRequest(req, res);
});

this.httpClientModuleManager.get(
'/bid-suggestion',
(req, res) => {
this.bidSuggestionHttpApiController.handleBidSuggestionRequest(req, res);
},
{ requestSchema: this.jsonSchemaService.bidSuggestionSchema() },
);
}

initializeBeforeMiddlewares() {
this.httpClientModuleManager.initializeBeforeMiddlewares();
}

async initializeVersionedListeners() {
const descendingOrderedVersions = this.apiVersions.sort((a, b) => b.localeCompare(a));
const mountedLatestRoutes = new Set();

for (const version of descendingOrderedVersions) {
for (const [name, route] of Object.entries(this.apiRoutes[version])) {
const { method, path, options } = route;
const camelRouteName = stringUtil.toCamelCase(name);
const controller = `${camelRouteName}HttpApiController${stringUtil.capitalize(
version,
)}`;
const schema = `${camelRouteName}Schema`;

if (
schema in this.jsonSchemaService &&
typeof this.jsonSchemaService[schema] === 'function'
) {
// eslint-disable-next-line no-await-in-loop
options.requestSchema = await this.jsonSchemaService[schema](version);
}

const middlewares = this.httpClientModuleManager.selectMiddlewares(options);
const callback = (req, res) => {
this[controller].handleRequest(req, res);
};

this.routers[version][method](path, ...middlewares, callback);

if (!mountedLatestRoutes.has(route.name)) {
this.routers.latest[method](path, ...middlewares, callback);
mountedLatestRoutes.add(route.name);
}
}
}
}

initializeRouters() {
for (const version of this.apiVersions) {
this.httpClientModuleManager.use(`/${version}`, this.routers[version]);
}

this.httpClientModuleManager.use('/latest', this.routers.latest);
this.httpClientModuleManager.use('/', this.routers.v0);
}

initializeAfterMiddlewares() {
this.httpClientModuleManager.initializeAfterMiddlewares();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import BaseController from './base-http-api-controller.js';
import BaseController from '../base-http-api-controller.js';

class BidSuggestionController extends BaseController {
constructor(ctx) {
Expand All @@ -8,7 +8,7 @@ class BidSuggestionController extends BaseController {
this.shardingTableService = ctx.shardingTableService;
}

async handleBidSuggestionRequest(req, res) {
async handleRequest(req, res) {
if ((await this.repositoryModuleManager.getPeersCount(req.query.blockchain)) === 0)
this.returnResponse(res, 400, {
code: 400,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import {
CONTENT_ASSET_HASH_FUNCTION_ID,
DEFAULT_GET_STATE,
ERROR_TYPE,
} from '../../constants/constants.js';
import BaseController from './base-http-api-controller.js';
} from '../../../constants/constants.js';
import BaseController from '../base-http-api-controller.js';

class GetController extends BaseController {
constructor(ctx) {
Expand All @@ -18,7 +18,7 @@ class GetController extends BaseController {
this.validationService = ctx.validationService;
}

async handleGetRequest(req, res) {
async handleRequest(req, res) {
const operationId = await this.operationIdService.generateOperationId(
OPERATION_ID_STATUS.GET.GET_START,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { createRequire } from 'module';
import BaseController from './base-http-api-controller.js';
import BaseController from '../base-http-api-controller.js';

const require = createRequire(import.meta.url);
const { version } = require('../../../package.json');
const { version } = require('../../../../package.json');

class InfoController extends BaseController {
handleInfoRequest(req, res) {
handleRequest(_, res) {
this.returnResponse(res, 200, {
version,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import BaseController from './base-http-api-controller.js';
import { OPERATION_ID_STATUS } from '../../constants/constants.js';
import BaseController from '../base-http-api-controller.js';
import { OPERATION_ID_STATUS } from '../../../constants/constants.js';

class LocalStoreController extends BaseController {
constructor(ctx) {
Expand All @@ -9,7 +9,7 @@ class LocalStoreController extends BaseController {
this.dataService = ctx.dataService;
}

async handleLocalStoreRequest(req, res) {
async handleRequest(req, res) {
const operationId = await this.operationIdService.generateOperationId(
OPERATION_ID_STATUS.LOCAL_STORE.LOCAL_STORE_INIT_START,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import BaseController from './base-http-api-controller.js';
import BaseController from '../base-http-api-controller.js';
import {
ERROR_TYPE,
OPERATION_ID_STATUS,
OPERATION_STATUS,
CONTENT_ASSET_HASH_FUNCTION_ID,
LOCAL_STORE_TYPES,
} from '../../constants/constants.js';
} from '../../../constants/constants.js';

class PublishController extends BaseController {
constructor(ctx) {
Expand All @@ -16,7 +16,7 @@ class PublishController extends BaseController {
this.repositoryModuleManager = ctx.repositoryModuleManager;
}

async handlePublishRequest(req, res) {
async handleRequest(req, res) {
const operationId = await this.operationIdService.generateOperationId(
OPERATION_ID_STATUS.PUBLISH.PUBLISH_START,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import BaseController from './base-http-api-controller.js';
import BaseController from '../base-http-api-controller.js';

import { OPERATION_ID_STATUS } from '../../constants/constants.js';
import { OPERATION_ID_STATUS } from '../../../constants/constants.js';

class QueryController extends BaseController {
constructor(ctx) {
Expand All @@ -9,7 +9,7 @@ class QueryController extends BaseController {
this.operationIdService = ctx.operationIdService;
}

async handleQueryRequest(req, res) {
async handleRequest(req, res) {
const { query, type: queryType } = req.body;

const operationId = await this.operationIdService.generateOperationId(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export default (blockchainImplementationNames) => ({
export default (argumentsObject) => ({
type: 'object',
required: [
'blockchain',
Expand All @@ -10,7 +10,7 @@ export default (blockchainImplementationNames) => ({
],
properties: {
blockchain: {
enum: blockchainImplementationNames,
enum: argumentsObject.blockchainImplementationNames,
},
epochsNumber: {
type: 'number',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GET_STATES } from '../../../constants/constants.js';
import { GET_STATES } from '../../../../constants/constants.js';

export default () => ({
type: 'object',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { LOCAL_STORE_TYPES } from '../../../constants/constants.js';
import { LOCAL_STORE_TYPES } from '../../../../constants/constants.js';

export default (blockchainImplementationNames) => ({
export default (argumentsObject) => ({
type: 'array',
items: {
type: 'object',
Expand All @@ -19,7 +19,7 @@ export default (blockchainImplementationNames) => ({
minItems: 1,
},
blockchain: {
enum: blockchainImplementationNames,
enum: argumentsObject.blockchainImplementationNames,
},
contract: {
type: 'string',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export default (blockchainImplementationNames) => ({
export default (argumentsObject) => ({
type: 'object',
required: ['assertionId', 'assertion', 'blockchain', 'contract', 'tokenId'],
properties: {
Expand All @@ -15,7 +15,7 @@ export default (blockchainImplementationNames) => ({
minItems: 1,
},
blockchain: {
enum: blockchainImplementationNames,
enum: argumentsObject.blockchainImplementationNames,
},
contract: {
type: 'string',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { QUERY_TYPES, TRIPLE_STORE_REPOSITORIES } from '../../../constants/constants.js';
import { QUERY_TYPES, TRIPLE_STORE_REPOSITORIES } from '../../../../constants/constants.js';

export default () => ({
type: 'object',
Expand Down
Loading
Loading