Skip to main content
Version: 1.x

Introduction

warning

This is documentation for Nammatham 1.x, which is no longer actively maintained. For up-to-date documentation, see the latest version (2.x).

Nammatham Logo

Azure Function Lightweight frameworks with DI, providing type safe function triggers and bindings

Build & Test codecov npm version npm download

VersionStatusAzure Functions Node.js LibBranchBuild Status
v1.xMaintenancev3.xv1.xBuild & Test codecov
v2.xAlphav4.xmainBuild & Test codecov

Please note that Nammatham v2 is currently in its Alpha stage and is intended for internal use only. As we actively develop and refine the platform, be aware that the API may undergo frequent changes. Tracking v2 Roadmap

Note: Nammatham v1 is currently in maintenance mode. no new features are actively being developed

Description

Nammatham (นามธรรม in Thai, pronounced /naam ma tham/, means abstract in Thai) is Azure Function Nodejs Lightweight framework with Dependency Injection. Provide type safety wrapping function.json

Talks

Empowering TypeScript on Azure Functions with Nammatham, Azure Open Source Day @ Microsoft Thailand, 25 Mar 2023 (Thai speech, subtitle will added later)

Compatibility with Azure Functions

Introduction

Nammatham is a framework that allows you to use Azure Functions with TypeScript and decorators. It provides pre-defined JSON binding objects and utility functions, such as httpTrigger, to make it easier to create Azure Functions.

Example:

import { AuthorizationLevel, BaseFunction, functionName, httpTrigger } from "nammatham";
import { HttpRequest } from "@azure/functions";

@functionName("GetUsers", httpTrigger(AuthorizationLevel.Anonymous, ["get"]))
export class UserFunction extends BaseFunction {

public override execute(req: HttpRequest): void {
const name = req.query.name;
this.res.send(`hello get user with ${name}`);
}
}

Features

Installation

You can install nammatham using npm:

npm install nammatham inversify reflect-metadata --save

For the InversifyJS, please refer the documentation for usage.

Starter Project

Getting Started

Full examples please, go to examples directory

1. Basic

This is basic to use partially type support, you can follow steps below:

  1. define startup.ts (or any name)

    // File: src/startup.ts
    import 'reflect-metadata';
    import { NammathamApp } from 'nammatham';
    import { SampleHttpFunction } from './functions/sample-http.function';

    const builder = NammathamApp.createBuilder(__filename);
    builder.addFunctions(SampleHttpFunction);
    builder.build();

    export default builder.getApp();
  2. Write a function handler, extend with BaseFunction we will auto inject Azure Function's Context

    // src/functions/sample-http.function.ts
    import { AuthorizationLevel, BaseFunction, functionName, httpTrigger } from 'nammatham';
    import { HttpRequest } from '@azure/functions';

    @functionName('SampleHttp', httpTrigger(AuthorizationLevel.Anonymous, ['get']))
    export class SampleHttpFunction extends BaseFunction {
    public override execute(req: HttpRequest): void {
    const name = req.query.name;
    const message = `hello get user with ${name}`;
    this.context.log(message);
    this.res.send(message);
    }
    }
  3. Add Azure Functions files at root

    • host.json
    • local.settings.json
  4. Run ts-node to generate all Azure Functions

    export nammatham_env=build; ts-node src/startup.ts && tsc
  5. Start Azure Functions

    func start

2. Handle function.json config by yourself

This method will support full support type when bindings config is set, for example below:

you can define your own function.json in Typescript object (as you can see the variable bindings), this will binding type into this.context.bindings.

import { BaseFunction, binding, functionName } from 'nammatham';

const bindings = [
binding.httpTrigger({ name: 'req' as const }), // make string to literal type
binding.http({ name: 'res' as const }), // make string to literal type
] as const;

@functionName('GetUser', ...bindings)
export class UserFunction extends BaseFunction<typeof bindings> {

public override execute() {
const { req } = this.context.bindings;
// ^---- `req` will be type HttpRequest
const name = req.query.name;
this.context.res = {
body: `hello get user with ${name}}`,
};
}
}

3. Add Services

// src/startup.ts
import 'reflect-metadata';
import { NammathamApp } from 'nammatham';
import { UserService } from './services/user.services';
import { UserFunction } from './functions/user.function';

const builder = NammathamApp.createBuilder(__filename);
builder.addFunctions(UserFunction);
builder.configureServices(services => {
services.addSingleton(Service);
// services.addScoped(Service);
// services.addTransient(Service);
});
builder.build();

export default builder.getApp();

define a function handler

import { AuthorizationLevel, BaseFunction, functionName, httpTrigger } from 'nammatham';
import { HttpRequest } from '@azure/functions';
import { UserService } from '../services/user.service';
import { inject } from 'inversify';

@functionName('GetUsers', httpTrigger(AuthorizationLevel.Anonymous, ['get']))
export class UserFunction extends BaseFunction {

constructor(@inject(UserService) private userService: UserService){
super();
}

public getUsers(): void {
const { req } = this.context.bindings;
const name = req.query.name;
const message = `hello get user with ${name}, service data: ${this.userService.getData()}`;
this.context.log(message);
this.res.send(message);
}
}

service:

import { injectable } from 'inversify';

@injectable()
export class UserService {
constructor() {}

public getData() {
return `Hey I'm service`;
}
}

Using Inversify API for Binding Services

In some cases, if you want to binding services with Inversify Container by yourself. In the startup file, you can simply get the Container from builder.container as shown in the example below:

// src/startup.ts
import 'reflect-metadata';
import { NammathamApp } from 'nammatham';
import { UserService } from './services/user.services';
import { UserFunction } from './functions/user.function';

const builder = NammathamApp.createBuilder(__filename);
builder.addFunctions(UserFunction);
// Using Inversify Container API
builder.container.bind(Service).toSelf();

builder.build();

export default builder.getApp();

Inspiration

Author

  • Thada Wangthammang, Software Engineer, Thailand