To Introduction

Microservice Facade

Step 5. Services and versioning

A facade’s RESTful operations are implemented by REST services, which receive external requests and delegate their execution to operations.

To process requests made to the API’s first version, let’s create a file named FacadeServiceV1.ts in the services/version1 folder with the following code:

/src/services/version1/FacadeServiceV1.ts

import { IReferences } from 'pip-services3-commons-node';
import { ConfigParams } from 'pip-services3-commons-node';
import { RestService } from 'pip-services3-rpc-node';

import { AuthorizerV1 } from './AuthorizerV1';

import { SessionsOperationsV1 } from '../../operations/version1/SessionsOperationsV1';
import { BeaconsOperationsV1 } from '../../operations/version1/BeaconsOperationsV1';

export class FacadeServiceV1 extends RestService {
    private _sessionsOperations = new SessionsOperationsV1();
    private _beaconsOperations = new BeaconsOperationsV1();

    public constructor() {
        super();
        this._baseRoute = "api/v1"
    }

    public configure(config: ConfigParams): void {
        super.configure(config);

        this._sessionsOperations.configure(config);
        this._beaconsOperations.configure(config);
    }

    public setReferences(references: IReferences): void {
        super.setReferences(references);

        this._sessionsOperations.setReferences(references);
        this._beaconsOperations.setReferences(references);
    }

    public register(): void {
        let auth = new AuthorizerV1();

        // Restore session middleware
        this.registerInterceptor('',
            (req, res, next) => { this._sessionsOperations.loadSession(req, res, next); });

        this.registerContentManagementRoutes(auth);
        this.registerUsersRoutes(auth);
    }

    private registerContentManagementRoutes(auth: AuthorizerV1): void {
        // Beacons routes
        this.registerRouteWithAuth('get', '/beacons', null, auth.admin(),
            (req, res) => { this._beaconsOperations.getBeacons(req, res); });
        this.registerRouteWithAuth('get', '/beacons/{id}', null, auth.owner('user_id'),
            (req, res) => { this._beaconsOperations.getBeaconById(req, res); });
        this.registerRouteWithAuth('get', '/beacons/udi/{udi}', null, auth.owner('user_id'),
            (req, res) => { this._beaconsOperations.getBeaconByUdi(req, res); });
        this.registerRouteWithAuth('post', '/beacons', null, auth.admin(),
            (req, res) => { this._beaconsOperations.createBeacon(req, res); });
        this.registerRouteWithAuth('put', '/beacons', null, auth.admin(),
            (req, res) => { this._beaconsOperations.updateBeacon(req, res); });
        this.registerRouteWithAuth('del', '/beacons', null, auth.admin(),
            (req, res) => { this._beaconsOperations.deleteBeaconById(req, res); });
        this.registerRouteWithAuth('post', '/beacons/position', null, auth.signed(),
            (req, res) => { this._beaconsOperations.calculatePosition(req, res); });
    }

    private registerUsersRoutes(auth: AuthorizerV1): void {
        // Session Routes
        this.registerRouteWithAuth('post', '/users/signup', null, auth.anybody(),
            (req, res) => { this._sessionsOperations.signup(req, res); });
        this.registerRouteWithAuth('post', '/users/signin', null, auth.anybody(),
            (req, res) => { this._sessionsOperations.signin(req, res); });
        this.registerRouteWithAuth('post', '/users/signout', null, auth.anybody(),
            (req, res) => { this._sessionsOperations.signout(req, res); });
    }
}

The FacadeServiceV1 component extends the standard RestService, which implements the majority of the component’s basic functionality. All that we have left to do is define some routes and delegate their processing to the operations we defined in the previous steps.

A base route is defined in the constructor, which contains the API version that is implemented in the service.

In the register method, before we register our routes, we make sure to register the loadSession interceptor, which will be loading user sessions using the parameters set in the REST requests.

Next, the routes are registered, access limits are set up using our Authorizer, and request handlers are defined using the business methods we implemented in our REST operation sets. For the sake of convenience, the registration functions are divided into 2 groups, each of which belongs to a specific operation-component.

When implementing a new version of the API, the following must be done:

  1. Implement new REST operations or modify a copy of the existing ones;
  2. Create a new FacadeServiceVx and set a new “/api/vx” base route;
  3. Register routes for the new API and delegate their processing to the newly added and to already existing REST operations.

Continue on to Step 6 - Testing Operations to see how we can automate the testing of the service and operations we’ve created, including the authentication and authorization of requests.