speedi
v1.3.0
Published
Speedy, all-in-one web application framework
Downloads
11
Readme
speedi
Speedy, all-in-one web application framework
Initialization
Before the app can run, Config
object should be initialized with the init
function. This function returns a promise that if fulfilled, the app can be created.
The argument to the init
function should be an object with the following format:
{
amqp: object({
host: string().required(),
password: string().optional().default('guest'),
port: number().optional().default(5672),
protocol: string().optional().default('amqp'),
username: string().optional().default('guest'),
}).optional(),
app: object({
nodeEnv: string().optional().default('development'),
}).optional().default({
nodeEnv: 'development',
}),
authentication: object({
secretKey: string().required(),
tokenLifeTime: number().optional().default(30 * 24 * 60 * 60 * 1000),
}).required(),
dataStore: object({
prefix: string().empty('').optional().default(''),
type: string().optional().default('redis'),
}).optional().default({
prefix: '',
type: 'redis',
}),
redis: object({
host: string().required(),
password: string().empty('').optional().default(''),
port: number().optional().default(6379),
protocol: string().empty('').optional().default(''),
username: string().empty('').optional().default(''),
}).required(),
}
For example:
Config.init({
amqp: {
host: '127.0.0.1',
},
authentication: {
secretKey: 'abcdefg',
},
redis: {
host: '127.0.0.1',
},
});
Creating an App
After Config
object is initialized and the returning promise is fulfilled, the app can be created.
const app = new App(options);
options
for the app includes an string name
, an optional http
server options, and an optional rpc
server options. http
server options should be in the following format.
http: {
host: string;
port: number;
protocol?: 'http' | 'https';
}
rpc
server options should be in the foloowing format:
rpc: {
queueNames: string[];
}
An example for creating an app is as follows:
const app = new App({
http: {
host: '127.0.0.1',
port: 9000,
protocol: 'http',
},
name: 'testApp',
rpc: {
queueNames: ['local_test_queue'],
},
});
Running the App
To run the app, run
method should be called. For example:
app.run();
Adding a Route
To add a route to all defined servers, addRoutes
method on the app instance should be called with an object implementing the following interface. This methods accepts both a single route options objects and array of them.
interface IRouteOptions {
name: string;
description: string;
method: RouteMethod;
path: string;
controller: (...args: any[]) => Promise<any>;
authentication?: IAuthenticationOptions;
files?: boolean;
payload?: (request: express.Request) => any;
validate?: Joi.SchemaMap;
rateLimit?: IRateLimiterOptions;
cache?: ICacherOptions;
}
Route method accepts values from RouteMethod
enum with the following definition:
enum RouteMethod {
Get,
Post,
Put,
Patch,
Delete,
}
controller
must be an async function (returns a promise) and it will be called with the object returned from the payload
function.
authentication
object should implement the following interface:
files
item is a boolean value, which if set to true, adds files
array to the request object in payload
function. The array will contain attached files with the following fields: fieldname
, originalname
, encoding
, mimetype
, size
, and buffer
.
interface IAuthenticationOptions {
customAuthenticator?: (token: IAuthenticationToken) => boolean;
renewToken?: boolean;
roles: string[];
}
rateLimit
object should implement the following interface:
interface IRateLimiterOptions {
duration: number;
allowedBeforeDelay: number;
maximumDelay: number;
allowedBeforeLimit: number;
message?: string;
keyGenerator?: (req: express.Request | IRpcRequest) => string;
key: string;
}
cache
object should implement the following interface:
interface ICacherOptions {
expire: number;
authBased: boolean;
}
Below is an example of adding a route:
app.addRoutes({
authentication: {
renewToken: true,
roles: ['user'],
},
cache: {
authBased: false,
expire: 10,
},
controller: async ({ files, id, name }) => {
return {
id,
message: `Hello ${name}! ${files.length} files received.`,
timestamp: Date.now(),
};
},
description: 'Get user information',
files: true,
method: RouteMethod.Post,
name: 'get_user',
path: '/user/:id',
payload: (req) => ({
files: req.files,
id: req.params.id,
name: req.body.name,
}),
rateLimit: {
allowedBeforeDelay: 10,
allowedBeforeLimit: 20,
duration: 60,
key: '',
maximumDelay: 30 * 1000,
},
validate: {
files: Joi.array().required(),
id: Joi.string().required(),
name: Joi.string().required(),
},
});
Send RPC Request to Other Services
To communicate between services, RPC requests can be sent using the send
method of the RpcSender
class. The method is an async function that returns a promised, which if fulfilled, contains the response for the request. The argument for the send
method should implement the following interface:
IRpcSenderRequest {
service: string;
name?: string;
method?: RouteMethod;
path?: string;
authenticationToken?: string;
payload?: any;
}
An example of sending an RPC request to a service called local_test_queue
and a processor (e.g., route) called local_test_queue
:
const response = await RpcSender.send({
authenticationToken: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6Ikprg0ofdyjjQbS1HEPr3xhM',
name: 'create_user',
payload: {
id: '123',
name: 'Dear User',
},
service: 'user_management',
});