From de871c240c134e1ac7bb374b6adb5acc6119802d Mon Sep 17 00:00:00 2001 From: Divinewill Date: Sat, 6 Apr 2024 01:01:38 +0100 Subject: [PATCH 1/4] chore: minor changes --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5c3daca..e8b3742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@blinkclaud/octobus", - "version": "0.3.0", + "version": "0.1.0", "description": "A toolkit for Blink HQ's microservices", "author": "Blink HQ", "private": false, From 56c0d78a72696f0e226aea3850ed2b1eb81aa9f8 Mon Sep 17 00:00:00 2001 From: Divinewill Date: Sat, 6 Apr 2024 01:21:01 +0100 Subject: [PATCH 2/4] patch: modified readme file --- README.md | 91 +++++++++++++++++++++++++++++++++++----------------- package.json | 2 +- 2 files changed, 63 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 210b68e..de65c3f 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,82 @@ -# Blink Base Service +# Blink Octobus -## Description +![Github Actions](https://github.com/blinkafrica/octobus/actions/workflows/build-test.yml/badge.svg) +[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) -This is the base service for the Blink project. It acts as a template for other services to be built on top of. It provides a basic structure for a service, including a database connection, a message queue connection, and a basic REST API. +## About -## Tools +Octobus is a library that provides utility functions for building microservices such as: -- Docker -- RabbitMQ -- NestJS -- TypeORM -- PostgreSQL +- Interservice communication (via REST) +- Subscribing to events from RabbitMQ queues. +- Logging +- Authentication -## Installation +## Getting Started + +These instructions will get you a copy of the project up and running on your local machine for development purposes. + +### Prerequisites + +The following are required for the best use of Octobus: + +- Package Dependencies + - NodeJs (v14 or higher) + - Yarn + - Typescript (v4.4 or higher) +- A basic understanding of nodejs and typescript with a good knowledge of nestjs would be an added advantage. + +### Installation + +To install Octobus, run the following command in your terminal ```bash -yarn install +yarn install --save @blinkclaud/octobus reflect-metadata ``` -## Running the app +To upgrade to a specific version run this command ```bash -# development -$ yarn run start +yarn upgrade @blinkclaud/octobus@version +``` + +To upgrade to latest version run this command -# watch mode -$ yarn run start:dev +```bash +yarn upgrade @blinkclaud/octobus --latest +``` -# production mode -$ yarn run start:prod +> Note: Octobus requires Typescript (>= v4.4), as well as the `Decorator` experimental feature. Therefore, the following config options should be present in your `tsconfig.json` file: + +```json +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["es2017", "esnext.asynciterable", "dom"], + "types": ["reflect-metadata"], + "module": "commonjs", + "moduleResolution": "node", + "experimentalDecorators": true, + "emitDecoratorMetadata": true + } +} ``` -## Test +## Guides -```bash -# unit tests -$ yarn run test +Below are links to detailed explanations to the various features of Octobus as well as practical examples: -# e2e tests -$ yarn run test:e2e +- [HTTP (Interservice Comunication)](docs/HTTP.md) +- [QueueManager (subscribing to RabbitMQ queues)](docs/Manager.md) +- [Authentication](docs/Authentication.md) +- [Logging](docs/Logging.md) -# test coverage -$ yarn run test:cov -``` +## References and Helpful Links -## License +The following links would further aid the understanding of Octobus -Blink is [MIT licensed](LICENSE). +- [Typescript Decorators](https://www.typescriptlang.org/docs/handbook/decorators.html) +- [AMPQ Client docs for NodeJs](http://www.squaremobius.net/amqp.node/channel_api.html) +- [Bunyan](https://github.com/trentm/node-bunyan#readme) +- [Axios](https://axios-http.com/docs/intro) +- [RabbitMQ messaging queues](https://www.rabbitmq.com/) diff --git a/package.json b/package.json index e8b3742..6e13d1a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@blinkclaud/octobus", - "version": "0.1.0", + "version": "0.2.0", "description": "A toolkit for Blink HQ's microservices", "author": "Blink HQ", "private": false, From ad3dddd9b69788072fd69f6a336106dd280baefe Mon Sep 17 00:00:00 2001 From: Divinewill Date: Sat, 6 Apr 2024 01:26:24 +0100 Subject: [PATCH 3/4] chore: change the deploy.yml pipeline --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 59141ed..2bd2778 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -80,4 +80,4 @@ jobs: yarn build npm publish --access public env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} From 48687d134feca7a77bfb25879048612c5c8d9d8f Mon Sep 17 00:00:00 2001 From: Divinewill Date: Sat, 6 Apr 2024 01:52:41 +0100 Subject: [PATCH 4/4] patch: added method that authenticates request for interservice communication --- package.json | 2 +- src/http/agent.ts | 2 +- src/http/wrapper.ts | 93 +++++++++++++++++++++++++-------------------- 3 files changed, 54 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 6e13d1a..5c3daca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@blinkclaud/octobus", - "version": "0.2.0", + "version": "0.3.0", "description": "A toolkit for Blink HQ's microservices", "author": "Blink HQ", "private": false, diff --git a/src/http/agent.ts b/src/http/agent.ts index 1e347c8..47cfe1a 100644 --- a/src/http/agent.ts +++ b/src/http/agent.ts @@ -65,7 +65,7 @@ export class HttpAgent { this.instance = axios.create({ ...defaultAxiosConfig, ...axiosConfig }); this.service = config.service; this.authConfig = { - secret: new TextEncoder().encode(config.secret), + secret: config.secret, scheme: config.scheme, timeout: config.timeout ?? '10s', }; diff --git a/src/http/wrapper.ts b/src/http/wrapper.ts index 3c41369..c81d795 100644 --- a/src/http/wrapper.ts +++ b/src/http/wrapper.ts @@ -1,16 +1,24 @@ +import { + APIError, + HttpError, + NoAuthorizationTokenError, + NoRequestIDError, + TimeoutError, +} from './errors'; import { AxiosError, AxiosInstance, AxiosRequestConfig } from 'axios'; -import { Request } from 'express'; + import FormData from 'form-data'; +import { Request } from 'express'; import { each } from 'lodash'; +import { encode } from './jwt'; import qs from 'qs'; import { v4 } from 'uuid'; -import { APIError, HttpError, NoRequestIDError, TimeoutError } from './errors'; // import { encode } from './jwt'; export interface AuthConfig { scheme: string; - secret: Uint8Array; + secret: string; timeout: string; } @@ -25,7 +33,7 @@ export type Action = () => Promise; */ export type Plugin = ( req: Partial>, - defer: (action: Action) => void, + defer: (action: Action) => void ) => void; export type RequestData = T | FormData | string; @@ -37,7 +45,7 @@ export class RequestWrapper { protected instance: AxiosInstance, protected service: string, protected authConfig: AuthConfig, - protected request: Partial>>, + protected request: Partial>> ) { this.request.headers = Object.assign({}, request.headers); } @@ -117,7 +125,7 @@ export class RequestWrapper { Object.assign( this.request.headers as object, - typeof key === 'string' ? { [key]: value } : key, + typeof key === 'string' ? { [key]: value } : key ); return this; @@ -145,38 +153,41 @@ export class RequestWrapper { * Attach session information to the request * @param reqSession authenticated express request or session object for headless request */ - // auth(reqSession?: Request | any) { - // const isReq = reqSession && 'headers' in reqSession; - - // if (isReq) { - // if (!reqSession.headers.authorization) { - // throw new NoAuthorizationTokenError(this.request.url); - // } - - // Object.assign(this.request.headers, { - // Authorization: reqSession.headers.authorization, - // }); - - // return this; - // } else { - // if (!reqSession) { - // reqSession = { service: this.service, request_time: new Date() } as any; - // } - - // // push till when the request is being made - // return this.defer(async () => { - // const token = await encode( - // this.authConfig.secret, - // this.authConfig.timeout, - // reqSession, - // ); - - // Object.assign(this.request.headers, { - // Authorization: `${this.authConfig.scheme} ${token}`, - // }); - // }); - // } - // } + auth(reqSession?: Request | any, payload?: Record) { + const isReq = reqSession && 'headers' in reqSession; + + if (isReq) { + if (!reqSession.headers.authorization) { + throw new NoAuthorizationTokenError(this.request.url); + } + + Object.assign(this.request.headers, { + Authorization: reqSession.headers.authorization, + }); + + return this; + } else { + if (!reqSession) { + reqSession = { + service: this.service, + request_time: new Date(), + ...payload, + } as any; + } + + // push till when the request is being made + return this.defer(async () => { + const token = await encode( + this.authConfig.secret, + this.authConfig.timeout, + reqSession + ); + Object.assign(this.request.headers, { + Authorization: `${this.authConfig.scheme} ${token}`, + }); + }); + } + } /** * Runs the API request and handles errors. @@ -195,7 +206,7 @@ export class RequestWrapper { throw new APIError( err.config!.url as string, err.response.status, - err.response.data, + err.response.data ); } else if (err.request) { if ( @@ -204,14 +215,14 @@ export class RequestWrapper { ) { throw new TimeoutError( err.config!.url as string, - err.config!.timeout as number, + err.config!.timeout as number ); } throw new HttpError(err.config!.url as string, err); } else { throw new Error(err.message); } - }, + } ); } }