A service locator SDK built with typescript
The Duffle Package contains interfaces, classes, and abstract classes that can be used to register API endpoints and service handlers to the Arrow Service Package.
This is the primary contract for creating DuffleRequest
Handler that can be mapped into the controller when registered.
When the Handler is created, two things must be configured on the constructor:
- method - Specifies what DuffleRequestMethods this handler supports
- endpoint- Specifies what API endpoint this will be accessible.
- When a certain
endpoint
already existed or is registered, this will be ignored. - Methods such as
getMethodType()
andgetEndpoint()
are non-overridable. These methods are there to retrievemethod
andendpoint
properties.
/*
* The method that is responsible to handle DuffleRequest when its handler is called.
*/
handle(request: DuffleRequest): Promise<DuffleResponse>;
/*
* Returns a DuffleRequestMethods enum string
*/
getEndpointMethod(): DuffleRequestMethods
/*
* Returns the absolute path where this handler can be accessed.
*/
getEndpoint(): string
import { BaseHandler, DuffleRequest, DuffleResponse } from 'duffle';
import BaseRepository from '../../../repository/baseRepository';
import { UserInfoRepositoryInteractor } from '../userInfoRepositoryInteractor';
export class AddUserInfoHandler extends BaseHandler {
private readonly interactor: UserInfoRepositoryInteractor;
constructor(db: BaseRepository) {
super();
this.method = 'POST';
this.endpoint = '/api/userinfo';
this.interactor = new UserInfoRepositoryInteractor(db); // todo: add to contructor parameter
}
public async handle(request: DuffleRequest): Promise<DuffleResponse> {
const firstName = request.body?.get('firstName');
const lastName = request.body?.get('lastName');
try {
const id = await this.interactor.add({
firstName: firstName,
lastName: lastName,
});
const res: DuffleResponse = {
status: 'OK',
body: id,
};
return res;
} catch (error) {
const res: DuffleResponse = {
status: 'ERROR',
body: error as string,
};
return Promise.reject(res);
}
}
}
This is the class responsible for registering endpoints of the service.
/*
* Gets all registered endpoints here.
*/
public getEndpoints(): BaseHandler[]
import { BaseHandlerRegistrator } from 'duffle/bin/baseHandlerRegistrator';
import BaseRepository from '../../repository/baseRepository';
import { AddUserInfoHandler } from './handlers/addUserInfoHandler';
export class UserInfoRegistrator extends BaseHandlerRegistrator {
constructor(db: BaseRepository) {
super();
this.handlers.push(new AddUserInfoHandler(db));
}
}
This is the class responsible for collecting registered handlers.
/*
* gets all collected handlers.
*/
public getHandlers(): Map<string, BaseHandler>
const db: FirebaseRepository = new FirebaseRepository(
FirebaseAccessor.getDb()
);
const collector = new HandlerRegistratorCollector([
new UserInfoRegistrator(db),
]);
This class is responsible for locating registered handlers.
/*
* locates registered handlers specified in the request url.
*/
public async resolve(request: DuffleRequest): Promise<DuffleResponse>
const resolver = new HandlerResolver(collector);
const body = new Map<string, any>();
body.set('firstName', 'John');
body.set('lastName', 'doe');
const request: DuffleRequest = {
method: 'POST',
url: '/api/userinfo',
body: body,
};
try {
const res = await resolver.resolve(request);
console.log(res);
} catch (error) {
console.error(error);
console.info('ERROR IS HANDLED CORRECTLY');
}
import { HandlerRegistratorCollector, HandlerResolver } from 'duffle';
import { UserInfoRegistrator } from './core-services/userInfoManagementService/userInfoRegistrator';
import FirebaseAccessor from './dataAccess/firebase/firebaseAccessor';
import { FirebaseRepository } from './dataAccess/firebase/firebaseRepository';
const Service = (): HandlerResolver => {
const db: FirebaseRepository = new FirebaseRepository(
FirebaseAccessor.getDb()
);
const collector = new HandlerRegistratorCollector([
new UserInfoRegistrator(db),
// Add more registrators here...
]);
const resolver = new HandlerResolver(collector);
return resolver;
};
export const service = Service(); // use service in UI
export type DuffleRequestMethods =
| 'GET'
| 'POST'
| 'PUT'
| 'DELETE'
| 'PATCH'
| 'HEAD'
| 'OPTIONS'
| 'TRACE'
| 'CONNECT';
export interface DuffleRequest {
method: DuffleRequestMethods;
url: string;
body?: Map<string, any> | Object | string;
}
export interface DuffleResponse {
status: DuffleStatus;
body: Map<string, any> | Object | string | null;
}
export type DuffleStatus = 'OK' | 'ERROR';