npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@altcrm/altexpress

v1.0.18

Published

NodeJs Express based backend engine

Readme

ALTEXPRESS Backend Engine

! Attention ! The engine is in development. Functionality can be changed.

Get started

  1. Create a controller:
import { Request, Response, Controller, Get, Post, Put, Delete } from "@altcrm/altexpress";

@Controller("/clients")
export class ClientController {

    @Get("/:id")
    public async get(req: Request, res: Response): Promise<any> {
        const client = await service.findById(req.params.id);
        return { client };
    }
}
  1. Create a module:
import { Module } from "@altcrm/altexpress";

@Module({
    controllers: [ClientController]
})
export class ApplicationModule {}
  1. Create an application:
import { Application } from "@altcrm/altexpress";
import { ApplicationModule } from "./application.module";

async function startServer(port: number): Promise<void> {
    try {
        // create application and specify main module
        const app = new Application(ApplicationModule);

        // - !!! DO NOT USE !!! "express.urlencoded", "express.json" -
        // - already defined inside the "Application":
        // app.use(express.urlencoded({ extended: true }));
        // app.use(express.json());
        
        // - to specify global API prefix:
        // app.setGlobalPrefix("/api/v1");

        // - to specify middlewares:
        // app.use(morgan("dev"));
        // app.use(cors());

        console.log("Starting API...");
        await app.listen(port);
        console.log(`Server is running on port ${port}`);
    } catch (e) {
        console.error(e);
    }
}

// start the server
startServer(3000);

Tricks

Returning Method Result

  1. Simple. Just return a body (http status is 200 by default):
import { Request, Response, Controller, Post } from "@altcrm/altexpress";

@Controller("/clients")
export class ClientController {

    @Post("/")
    public async create(req: Request, res: Response): Promise<any> {
        const client = await service.create(req.body.dto);
        return { client };
    }
}
  1. Custom status and body. Return HttpResponse object:
import { Request, Response, Controller, Post, HttpResponse } from "@altcrm/altexpress";

@Controller("/clients")
export class ClientController {

    @Post("/")
    public async create(req: Request, res: Response): Promise<any> {
        const client = await service.create(req.body.dto);
        return new HttpResponse(201, { client });

        // or
        // return HttpResponse.successCreated({ client });
    }
}
  1. Error handling:
import { Request, Response, Controller, Post, HttpResponse, HttpException } from "@altcrm/altexpress";

@Controller("/clients")
export class ClientController {

    @Post("/")
    public async create(req: Request, res: Response): Promise<any> {
        try {
            // ...
        } catch (e: any) {
            return HttpResponse.error(e);

            // or
            // const err = new HttpException(400, e.message);
            // return HttpResponse.error(err);
        }
    }
}
  1. Error handling by engine. Application will catch and handle exceptions:
import { Request, Response, Controller, Post, HttpResponse, HttpException } from "@altcrm/altexpress";

@Controller("/clients")
export class ClientController {

    @Post("/")
    public async create(req: Request, res: Response): Promise<any> {
        // ...
        throw new HttpException(403, "Forbidden");

        // or
        // throw new Error("Custom error.");
    }
}

API Versioning

  1. Create controllers and modules for your business logic:
@Controller("/clients")
export class ClientControllerV1 {

    @Get("/:id")
    public async get(req: Request, res: Response): Promise<any> {
        // ...
    }
}

@Controller("/clients")
export class ClientControllerV2 {

    @Get("/:id")
    public async get(req: Request, res: Response): Promise<any> {
        // ...
    }
}

@Module({
    controllers: [ClientControllerV1]
})
export class ClientModuleV1 {}

@Module({
    controllers: [ClientControllerV2]
})
export class ClientModuleV2 {}
  1. Create modules for different API versions with prefix specified:
@Module({
    prefix: "/api/v1",
    modules: [ClientModuleV1]
})
export class ApiModuleV1 {}

@Module({
    prefix: "/api/v2",
    modules: [ClientModuleV2]
})
export class ApiModuleV2 {}
  1. Add modules to main application module:
@Module({
    modules: [ApiModuleV1, ApiModuleV3]
})
export class ApplicationModule {}

Now the both routes are available:

/api/v1/clients/11111
/api/v2/clients/22222

Middlewares

  1. Create a middleware (for example, guard for authentication):
import passport from "passport";

export default class Guard {
    public static Auth = passport.authenticate("jwt", { session: false });
}
  1. Add middleware to method decorator:
@Controller("/clients")
export class ClientController {

    @Get("/:id", Guard.Auth)
    public async get(req: Request, res: Response): Promise<any> {
        // ...
    }
}

Argument decorators

You can also use argument decorators to make your code cleaner:

@Controller("/clients")
export class ClientController {

    @Get("/search", Guard.Auth)
    public async search(
        @Query("search") search: string
    ): Promise<Client[]> {
        return await this.clientService.search(search);
    }

    @Get("/:id", Guard.Auth)
    public async get(
        @Params("id") id: string
    ): Promise<Client> {
        return await this.clientService.get(id);
    }

    @Put("/:id", Guard.Auth)
    public async update(
        @Params("id") id: string,
        @Body() dto: ClientUpdateDto
    ): Promise<Client> {
        return await this.clientService.update(id, dto);
    }

    @Patch("/:id", Guard.Auth)
    public async updatePhone(
        @Params("id") id: string,
        @Body("phone") phone: string
    ): Promise<Client> {
        return await this.clientService.updatePhone(id, phone);
    }
}

Use request and response objects

The controller is instantiated at each request. The instance has properties request, response, which can be accessed from every method. You can extends ControllerBase class to access this properties from every method.

@Controller("/clients")
export class ClientController extends ControllerBase {
    @Get("/:id", Guard.Auth)
    public async get(): Promise<Client> {
        const id = this.request.params.id // here
        return await this.clientService.get(id);
    }
}

Use dependency injection

You can use the dependency injection for controllers:

@Controller("/orders")
export class OrderController extends ControllerBase {
    public constructor(
        @Inject(OrderService) private readonly orderService: OrderService,
        @Inject(ClientService) private readonly clientService: ClientService,
        @Inject(DateTimeService) private readonly dateTimeService: DateTimeService,
    ) {
        super();
    }
}

or services:

export class OrderService {
    public constructor(
        @Inject(DateTimeService) private readonly dateTimeService: DateTimeService,
    ) { }
}

Dependencied should be registered in module's services section:

@Module({
    controllers: [
        OrderController,
        ClientController,
    ],
    services: [
        // Provide only the type for injection:
        OrderService,

        // It is an equivalent to:
        { type: ClientService, lifetime: ServiceLifetime.Scoped },

        // You can provide concrete implementation for injection:
        { type: DateTimeService, concrete: DateTimeServiceFake, lifetime: ServiceLifetime.Singleton },
    ],
})
export class OrderModule {}

Service lifetime could be one of the next values:

  • Scoped (default) - Service is instantiated once for every request.
  • Transient - Service is instantiated once for every call.
  • Singleton - Service is instantiated once for the entire module lifetime.