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 🙏

© 2024 – Pkg Stats / Ryan Hefner

inserve

v1.1.11

Published

Inserve aims to extend Express with a number of features that are vital while working on large codebases at scale. The goal is that it remains a very thin wrapper layer around Express, without significant divergence.

Downloads

18

Readme

Inserve

Inserve aims to extend Express with a number of features that are vital while working on large codebases at scale. The goal is that it remains a very thin wrapper layer around Express, without significant divergence.

Features

  • First-class support for dependency injection into route handlers (using Microsoft's tsyringe library)
  • A really great TypeScript experience. Typings built-in to the package, and used from the start, not as an afterthought.
  • Compatibility with everything else that is made for Express. We don't change the fundamentals at all.
  • BYOE: "Bring your own Express." We depend on Express and tsyringe as peer dependencies. The versions used in your project will be used by Inserve also.

Example #1 - Hello World

import 'reflect-metadata';
import { Server, Handler } from 'inserve';
import { Request, Response } from 'express';

// Define a route handler class. These can be used
// as middleware, endpoints, etc.
class HelloWorld implements Handler {

    public handle(req: Request, res: Response) {
        res.send('Hello world!');
    }

}

// Create and start the server
const server: Server = new Server();
server.get('/', HelloWorld);
server.listen(8080);

Pretty simple. But, this code is longer than the equivalent code in Express! So surely, there is a useful example, right? Right, that's where dependency injection comes in!

Example #2 - Dependency Injection (w/ tsyringe)

import 'reflect-metadata';
import { InjectionToken, injectable, inject } from 'tsyringe';
import { Server, Handler } from '../src';
import { Request, Response } from 'express';

/**
 * This injection token can be used to inject / resolve a database implementation
 */
const DATABASE_TOKEN: InjectionToken<IDatabase> = Symbol('DATABASE_TOKEN');

/**
 * Interface, which defines behaviors but not the specifics of how they are performed
 */
interface IDatabase {

    /**
     * Performs some user authentication check. I am not suggesting that this is a good
     * way to do this sort of thing. This example is used for illustrative purposes only.
     * @param token the user's authentication token
     */
    checkUserAuth(token: string): Promise<boolean>;

}

/**
 * Implementation, which defined implementation details for the aforementioned behaviors
 */
class MyDatabase implements IDatabase {

    public async checkUserAuth(token: string): Promise<boolean> {

        // Perform some check here. This is obviously only an example, and will allow anyone
        // with token 'hello'.
        return (token === 'hello');

    }

}

@injectable()
class RequireAccessToken implements Handler {

    /**
     * The database implementation is injected here. This middleware is agnostic
     * as it pertains to the specific implementation used. It just needs any
     * database that is wired up to work.
     */
    public constructor(
        @inject(DATABASE_TOKEN) private database: IDatabase) {}

    public async handle(req: Request, res: Response): Promise<void> {

        // Get the token from headers
        const token: string | undefined = req.headers.authorization?.replace(/^Bearer\s+/i, '');
        if (!token) res.status(401).send('Unauthorized. No access token provided.');

        // Check the user authentication
        const authenticated: boolean = await this.database.checkUserAuth(token as string);
        if (!authenticated) res.status(401).send('Unauthorized. Invalid access token.');

        // If you're familiar with Express, when this function returns, 
        // the underlying `next()` function is called, moving control
        // to the next middleware / handler.

    }
}

class HelloWorld implements Handler {

    public handle(req: Request, res: Response) {
        res.send('Hello world!');
    }

}

// Create the server instance
const server: Server = new Server();
server.get('/', RequireAccessToken, HelloWorld);

// Inject our database implementation
server.getContainer().register(DATABASE_TOKEN, MyDatabase);

// Start the database
server.listen(8080);

Conclusion

For large codebases, where it's crucial to build generic components which can be used in multiple different environments, dependency injection is a must.

Inserve enables your Express servers to take advantage of dependency injection. Routes can define what services and values they need, and the upstream provider / environment can inject the appropriate implementation at runtime.

Hopefully you find this useful. I intend to add to this as needed for my other projects that depend on it; but, if you think of something you need, I an open to adding it too.