Skip to content

Build HTTP services with this; a Typescript REST framework based on Express using decorators and Angular style dependency injection

License

Notifications You must be signed in to change notification settings

alterior-mvc/alterior

Repository files navigation

Alterior CircleCI Join the chat at https://gitter.im/alterior-mvc/Lobby License npm

NPM | Github | API reference | Changelog

A framework for building well-structured applications and isomorphic libraries in Typescript.

Overview

Alterior is an isomorphic framework for building service-oriented applications composed of executable modules which participate in dependency injection and declare components.

Alterior's Modules are well-defined units of execution which have a defined lifecycle, and respond to standardized lifecycle events. This makes them suitable for use as a primary vehicle for top-level general purpose code, such as a server or even a desktop application.

Class Libraries

Alterior strives to provide a strong isomorphic base class library that fills the gaps between ECMAScript and larger BCLs like Java or .NET. In service of this, Alterior ships low-level libraries for handling decorators/annotations, errors and error base classes, dependency injection, an HTTP client, and more.

Getting Started

Alterior is not just a REST framework, but that's certainly it's most common usage.

import '@alterior/platform-nodejs';
import { WebService, Get, WebServerEngine } from '@alterior/web-server';
import { Application } from '@alterior/runtime';
import { ExpressEngine } from '@alterior/express';

WebServerEngine.default = ExpressEngine;

@WebService()
export class MyWebService {
    @Get('/service-info')
    info() {
      return { 
        service: 'my-web-service' 
      };
    }
}

Application.bootstrap(MyWebService);

For more information on building web services with Alterior, see @alterior/web-server.

Consuming your web service

A web service built with Alterior can be consumed on the client transparently. This is an example of a Transparent Service

import { MyWebService } from '@example/my-backend';
import { Component } from '@angular/core';

@Component({ selector: 'my-component', ... })
export class MyComponent {
  constructor(
    private service : MyWebService
  ) {
  }

  onButtonClicked() {
    let serviceInfo = await this.service.info();
    console.log(serviceInfo);
    // { service: 'my-web-service' }
  }
}

Transparent services are not limited to being used in Angular. The simplest way to consume a service on the frontend is to create it using Service.bootstrap()

import { Service } from '@alterior/runtime';
import { MyWebService } from '@example/my-backend';

let service = Service.bootstrap(MyWebService);

Creating a project

Start by installing the Alterior command line tooling:

npm install @alterior/cli -g

Then you can generate a new Alterior service:

alt new service my-web-service

A new folder called my-web-service will be created containing a fully formed Alterior project. To start the service, enter the new folder and call

npm start

To publish the project to NPM for use in your frontend, use

npm publish

Alterior automatically handles everything needed to build and publish your application, including removing your actual backend code if you have asked for that.

Do I have to use the CLI?

You can build an Alterior project using tsc (or any other Typescript compiler) if you wish, but not all of Alterior's features will be available. Transparent Services in particular are enabled via the Alterior CLI build process, so much of the benefits of that feature would be unavailable without additional work.

Additionally, Alterior's builtin build process emits runtime type reflection information for all elements, even when there are no decorators present. Typescript itself only emits type metadata for decorated elements, so you may have to add decorators where there are none are needed when Alterior is built by its own CLI.

If you choose not to use Alterior CLI's build step, you may want to use the ttypescript frontend instead of tsc and add a transform for emitting all type metadata. The one that Alterior uses is currently built-in to @alterior/cli, but we plan to roll it out as a standalone transformer in the near future.

Mechanics

Alterior is not just for building REST services. Here's a minimal single file example of an application that is something other than a @WebService.

import 'reflect-metadata';
import { Module, OnInit, AppOptions, Application } from '@alterior/runtime';

@Module()
export class AppModule implements OnInit {
    public altOnInit() {
        console.log('Hello world!');
    }
}

Application.bootstrap(AppModule);

This becomes useful because Alterior modules can participate in dependency injection and builtin lifecycle management functionality. A class decorated with @WebService() is also considered an @Module().

Dependency Injection

Bootstrapped classes can participate in dependency injection.

import 'reflect-metadata';
import { Module, OnInit, AppOptions, Application } from '@alterior/runtime';
import { Injectable } from '@alterior/di';

@Injectable()
export class WorldService {
  theWorld() {
    return 'world';
  }
}

@Injectable()
export class HelloService {
  constructor(
    private world : WorldService
  ) {
  }

  sayHello() {
    return `hello, ${this.world.theWorld()}`;
  }
}

@Module()
export class AppModule implements OnInit {
    constructor(
      private hello : HelloService
    ) {
    }

    public altOnInit() {
        console.log(this.hello.sayHello());
    }
}

Application.bootstrap(AppModule);

Lifecycle Management

Modules can have any of the following lifecycle methods which act as hooks for running custom behaviors

  • altOnInit() Called when the module is bootstrapped. Implement the OnInit interface when using this lifecycle method.
  • altOnStart() Called when the overall application is started. Implement the OnStart interface when using this lifecycle method.
  • altOnStop() Called when the overall application is stopped before exiting. Implement the OnStop interface when using this lifecycle method.
  • RolesService The notion of "roles" is used to allow a module to define or react to a certain class of functionality being started or stopped. For instance @/web-server adds a web-server role which can be enabled or disabled at configuration time to control whether the web server portion of the application is enabled or disabled. Similarly @/tasks adds a task-worker role. By default all roles are started when the application starts. This can be used to start only a specific portion of an application in a particular environment, for instance having the web server and task worker roles started in development, but splitting these into separate tiers in production.

For more information about lifecycle management, see the Roles section of the @/runtime documentation.

Packages

Alterior consists of the following individual NPM packages. You can pull in packages as you need them.

  • @alterior/annotations A system for decorating and introspecting standardized metadata on programmatic elements in Typescript

  • @alterior/common Provides many smaller quality-of-life utilities which can save you time while you build your applications.

  • @alterior/command-line Command line arguments handling

  • @alterior/cli The Alterior CLI tool

  • @alterior/di Provides a flexible Angular-style dependency injection framework based on injection-js

  • @alterior/http HTTP client library as an Alterior module (ported from @angular/http)

  • @alterior/logging A logging library which supports pluggable listeners and context-tracked logging using Zone.js

  • @alterior/platform-angular Provides support for loading Alterior modules into an Angular app, including the ability to access Alterior injectable services from Angular components and services. Use this to consume isomorphic libraries from within frontend apps written in Angular.

  • @alterior/platform-nodejs Provides support for bootstrapping an Alterior application within the Node.js server environment.

  • @alterior/rtti A Typescript transformer for emitting comprehensive runtime type information (RTTI)

  • @alterior/runtime An module-based dependency injection and lifecycle event system similar to that of Angular, suitable for use in Alterior libraries and applications.

  • @alterior/tasks A system for enqueuing and processing tasks using Redis as it's backing store (based on bull queue)

  • @alterior/web-server A system for building RESTful web services declaratively using classes & decorators

Compatibility

Using Alterior modules in Angular

You can use any browser-compatible Alterior module in Angular by using
@alterior/platform-angular:

import { AngularPlatform } from '@alterior/angular-platform';
import { MyAlteriorModule, MyAlteriorService } from '@my/alterior-module';

@NgModule({
  providers: [
    AngularPlatform.bridge(
      MyAlteriorModule,
      // ...
    )
  ]
})
export class AppModule {
  constructor(
    someAlteriorService : MyAlteriorService
  ) {
    console.log(`The following service was injected from an Alterior module:`);
    console.log(someAlteriorService);
  }
}

For more about using Alterior modules in Angular, see @alterior/platform-angular.

About

Build HTTP services with this; a Typescript REST framework based on Express using decorators and Angular style dependency injection

Topics

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages