1.1.10 • Published 2 years ago

@dimetrail/firebase v1.1.10

Weekly downloads
-
License
ISC
Repository
github
Last release
2 years ago

Dimetrail Firebase

A dependency injection framework for Firebase Cloud Functions.

Controller

A Controller is a class marked by the @Controller decorator (at @dimetrail/firebase/core/utils). It groups HTTP paths along with their handlers. The Controller class needs to be declared in a DtModule in order to load its cloud functions to firebase.

import {Controller} from "@dimetrail/firebase/core/utils";

@Controller({path: "my-path"})
class MyController {}

We can use dependency injection (DI) to access singleton objects within a DtModule.

@Controller({path: "my-path"})
class MyController {
  constructor(readonly Logger: logger) {}

  myMethod() {
    this.logger.log("hello world");
  }
}

HTTP Annotations

Methods in a Controller can be annotated with @get, @post, put, or patch (all at @dimetrail/firebase/core/https) to export them as Firebase cloud functions. All annotations take as argument an object with a path:string key.\ The annotation's handler method must take two arguments: Request and Response (both at @dimetrail/firebase/core/https).

import {get} from "@dimetrail/firebase/core/https";

@Controller({path: "notification"})
export class NotificationController {
  constructor(readonly NotificationDatabase: notificationDB) {}

  @get({path: "latest"})
  getLastNotification(req: Request, res: Response) {
    res.send(notificationDB.getLast());
  }
}

In the example above, the getLastNotification handler will be available at the path: notification/latest. Were we to declare the controller in a DtModule called "Message", the path would become message/notification/latest.\ \ Note: Adding "/" to the beginning of a path is optional.

DtModule

An DtModule is a class marked by the @DtModule decorator (at @dimetrail/firebase/core/utils). It groups (or scopes) Controllers with Injectables, and loads the cloud functions to firebase (along with their respective paths).\ A DtModule can take an optional path argument, which is used as a prefix for its controller paths.

import {DtModule} from "@dimetrail/firebase/core/utils";
import {MyController} from "./my-controller";

@DtModule({
  path: "my-path",
  controllers: [MyController],
  providers: [new Provider({provide: Logger})],
})
export class MyModule {}

Modules can import other modules via the imports key. When importing a module, all its Controllers and Injectables become available to the (importing) module's scope.

@DtModule({
  imports: [MyModule],
})
class MainModule {}

Root Module

This is the DtModule that ultimately exports the app resources to Firebase. All other modules should be imported here.

import {bootstrapModule} from "@dimetrail/firebase/core/utils";

@DtModule({
  imports: [MyModule],
})
class RootModule {}

export const main = bootstrapModule(new RootModule());

The bootstrapModule(DtModule) function is responsible for transforming the app resources into a single cloud function for Firebase. The cloud function uses express.js to serve its resources (see how).

Initializing global resources

Note that the file in which the root module is declared is a good location for other app initialization logics.

import * as admin from "firebase-admin";

admin.initializeApp(); // This runs before everything else.

@DtModule({
  imports: [MyModule],
})
class RootModule {}

export const main = bootstrapModule(new RootModule());

Fetching the Express.js app instance

The getExpressInstance(DtModule):Express method (at @dimetrail/firebase/core/utils) fetches the express instance used by your main cloud function. This could be useful for direct manipulations such as adding middleware.

import * as cors from "cors";
import {
  getExpressInstance,
  bootstrapModule,
} from "@dimetrail/firebase/core/utils";

@DtModule({
  imports: [MyModule],
})
class RootModule {}

const rootModule = new RootModule();

const app = getExpressInstance(rootModule);
app.use(cors({origin: true}));

export const main = bootstrapModule(rootModule);

Dependency Injection

Injectable

An Injectable is a class marked by the @Injectable decorator (at @dimetrail/firebase/core/utils). It marks a class as usable by a provider.

import {Injectable} from "@dimetrail/firebase/core/utils";

@Injectable()
export class MySanitizer {}

Provider

Singleton objects can be instantiated and shared at the DtModule level. We use a Provider object (at @dimetrail/firebase/core/utils) as shown below. Note that there are three ways to declare a provider.

import {Provider} from "@dimetrail/firebase/core/utils";
import {MyValidator, MySanitizer, MyLogger} from "./my-services";

@DtModule({
  controllers: [MyController],
  providers: [
    MyValidator, // Implictly created via DI.
    new Provider({provide: MySanitizer}), // Implictly created via DI.
    new Provider({
      provide: MyLogger,
      useValue: new MyLogger({url: "string-argument"}),
    }),
  ],
})
export class MyModule {}

Note: The providers are key'ed by class name; consequently, when two objects from the same class are provided, the latter overwrites the former.

Injecting

Provided objects can be injected into controllers that are declared in the same module. Arguments can be written in any order.

@Controller({path: "my-path"})
class MyController {
  constructor(readonly MyLogger: logger, readonly MySanitizer: sanitizer) {}
}

Middleware

DtModules, Controllers, and Http annotations may take in middleware handlers that run as precursors to get, post, put, and patch http handlers. For all the mentioned decorators, handlers are added using the runHttpAfter (at @dimetrail/firebase/core/utils).\

import {Controller, runHttpAfter} from "@dimetrail/firebase/core/utils";
import {Request, Response, get} from "@dimetrail/firebase/core/utils";

@Controller({
  runHttpAfter: [
    (req, res, next) => {
      // Performs middleware operations here.
      next();
    },
  ],
})
export class MyController {
  @get({path: "my-path"})
  myHandler(req: Request, res: Response){
    // This runs after the middleware above.
  }
}

Note: the middleware execution follows the array order. When runHttpAfter is used at multiple decorator levels, precedence is in the following order: DtModule, Controller, then http annotation;

1.1.10

2 years ago

1.1.9

2 years ago

1.1.8

2 years ago

1.1.7

2 years ago

1.1.6

2 years ago

1.1.5

2 years ago

1.1.4

2 years ago

1.1.3

2 years ago

1.1.2

2 years ago

1.1.1

2 years ago

1.1.0

2 years ago

1.0.7

2 years ago

1.0.6

2 years ago

1.0.5

2 years ago

1.0.4

2 years ago

1.0.3

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago