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

fuhttp-ts

v1.2.1

Published

a HTTP-server written in TypeScript using Node.js

Downloads

6

Readme

fuhttp-ts

Build Status

fuhttp

Web-server for nodejs written in TypeScript, highly inspired by this blog post. The server is built on top of the http package in nodejs.

Why another web-server package for nodejs? because I can (and because I didn't need all features provided by e.g. express)

Setup

Install the package

npm install fuhttp-ts

fuhttp-ts can now be included within your nodejs project using:

var fuhttp = require('fuhttp-ts');

For TypeScript:

import * as fuhttp from 'fuhttp-ts';

Manual Installation

Manual installation requires a clone of the repo.

Install dependencies defined in package.json

npm install

Run the rebuild script, as defined in packages.json. This will delete the build/ folder, compile all .ts files, create build/ folder where all .js files will reside, and append the license banner to each output file.

Documentation

Server

The Server class are used for handling HTTP requests and responses.

Constructor

Creating a new http-server:

constructor(port: number, host: string = null)

Where port is the tcp/ip-port which the server will listen for.

If host is set, only connections from host will be accepted.

var server = new fuhttp.Server(8080, 'localhost');

Here, connections made from client with origin-ip localhost connecting to the server on port 8080 is only accepted. If the HTTP-server should be made publicly available, hostname should be ignored.

Add Route

Adding a Route to match with an incoming HTTP-request:

Where route is a set of url-patterns. See Route for more information

add(path: string, route: Route): void

path is the parent sub-url, where route is accessible from.

let route = new Route('api');
... // Setup routes

server.add('/api', route);
server.add('/test', route);

The server can now be accesses the defined route object, both from /api and /test

Route lookup

Routing is implemented in a linked list inspired manner. The server only contains a parent route, which has a reference to its sub-routes. The routing uses this implementation to support faster lookup of routes for parsing, as opposed needing to loop through all added routes to find a matching route.

Add Middleware

A middleware is a set of instructions run before each request in handled by the Routes. See the Middleware section for more information about the available Middlewares

use(middleware: IMiddleware): void

Error Handling

The server may throw errors, e.g. if a route is not found. This is where the Error Functions come into play. The Server comes with some predefined error-handling functions, these can however be overwritten, which they also probably should.

| Status Code | Type | Event name | Method Name | |-------------|-------------------------------|-------------|----------------------------------| | 400 | Request Error | request | onRequestError(error, response) | | 444 | Response Error | response | onResponseError(error, response) | | 404 | Route Not Found | notfound | onNotFoundError(response) | | 405 | Method Not Allowed | notallowed | onMethodNotAllowed(supportedMethods, response) | | 413 | Request Data Too Large | overflow | onOverflowError(response) | | NA | Client Emits Error | clientError | onClientError(error, socket) | | NA | Server Closes | close | onClose() | | NA | Client Request A HTTP Upgrade | upgrade | onUpgrade() | | NA | Exception thrown from server method | exception | onException() |

Each error-handler can be set using the method as described in Method Name, or through the more general method:

on(event: string, func: Function): boolean

Where event is the Event Name as defined in the table above.

The provided example is both equivalent, defining a function to run when there's an error with a HTTP-request

server.onRequestError = function(error: Error, response: http.ServerResponse) {
    ...
};

server.on('request', function(error: Error, response: http.ServerResponse) {
    ...
});

Start Server

For the server to start accepting incoming requests, the server needs to be started:

listen(): void 

Your HTTP-server is now able to handle incoming HTTP-requests, as configured in your constructor. If no routes are added at this point, the application will throw an error.

server.listen();

Route

The Route class for parsing and matching incoming HTTP-requests based on an URL

Constructor

constructor(routeName: string = null)

Where routeName is the parent-pattern that will be matched against all incoming requests.

let route = new Route('api');

If the server is running locally, the route will be accessible from the url http://localhost/api. All incoming requests will be split on the first / (after the hostname), and a matching route will be searched for within that route.

let r1 = new Route('user');
let r2 = new Route('company');

When the server receives a HTTP-request: [hostname]/user, the r1 route will search for a match from one of its registered patterns, and ignore r2. This would prevent the HTTP-server from searching all the defined routes in both r1 and r2.

Add Url-Patterns

Requests against the HTTP-server can be done using these common HTTP-methods:

  • GET
  • POST
  • DELETE
  • PUT

What method to use when is really up to you, but you should however try to follow the convention. For a simple guide, visit restapitutorial.com

The format of each function is defined as following:

requestUrl: string, func: (req: http.IncomingMessage, res: http.ServerResponse, ...params: any[]) => void

requestUrl is the pattern which the route should match against.

Parameters are defined using the : notation infront of a keyword.

func is the function to call when a HTTP-request url matches the defined pattern in requestUrl. When a route matches, the first two parameters will always be:

  • req - The actual request made by a user, see the documentation on nodejs.org
  • res - The response to send to the user, see the documentation on nodejs.org

An undefined number of parameters is passed to func depending on the defined pattern in requestUrl. If no parameters is defined in requestUrl, only the first two parameters will be set.

route.get('api/:id', function(req, res, id) {
    // HTTP/GET
    // Variable id corresponds to data passed in :id of the requestUrl, e.g. api/1 => id = 1
    ...
    
});

route.get('api/name/:name', function(req, res, name) {
    // HTTP/GET
    // api/name/hello => name = hello
    ...
});

route.get('user/:id', function(req, res, id, optional) {
    // HTTP/GET
    // user/1 => id = 1
    ...
});

route.get('hello/world', function(req, res) {

});

route.post(...) , route.delete(...), route.put(...) can be replaced with route.get(...) in the provided example.

Sub Routing

Sub-routing is a way of combining or creating nested routes, and is possible through

add(path: string, route: Route): void
let route = new Route();
let userRoute = new Route();
let baseRoute = new Route();

route.add('/user', user);
route.add('/base', base);

Here, the userRoute will be accessible through /user, and baseRoute through base/

NOTE: If both route and baseRoute has a set of colliding route-patterns, only the parent-route will be matched, in this case route.

Middleware

Each Route can run a middleware before a matched route is called. As opposed to a server middleware, which is run on each request, a route middleware is only run for a single route. Use-cases could be to lock-down certain routes for authentication.

use(middleware: IMiddleware): void

More information about middlewares, and the different types can be found in the middleware section below

Middlewares

A Middleware is a set of instructions to run before a matching route is searched for. Middlewares are used for altering the HTTP-request and HTTP-response objects before they are passed to a matching route function.

Multiple middlewares are included in this package:

CORS

Enables cross-origin requests on the server.

...
let cors = new Cors({...}); // See documentatino for options below
server.use(cors);
Options
  • cookies: boolean
    • default = false
    • Whether the allow-credentials header should be set, supporting the use of cookies with CORS (Access-Control-Allow-Credentials)
  • methods: HTTP_METHODS[]
    • default = null => uses HTTP-method used in HTTP-request
    • Supported http-methods for a route, defaults to current request method (Access-Control-Request-Method)
  • maxage: number
    • default = 1
    • How many seconds a response to be cached for CORS (Access-Control-Max-Age)

The CORS middleware are implemented following the guide(s) found at enable-cors.org

BodyJsonParse

Parsing of body-data to json, using querystring or JSON.parse.

...
server.use(new BodyJsonParse());

This middleware exposes a .body variable as an object type to the http.ServerResponse parameter.

function(request, response) {
    let bodyData:{} = request.body;
    
    response.write('post id: ' + bodyData.id);
}

JsonResponse

Generates a json response from an input js object. Exposes a method json() to the response object, and automatically ends the response.

function(request, response) {
    response.json({
        id: 12,
        description: "lorem ipsum"
    });
}

HTML response:

{
    "id": 12,
    "description": "lorem ipsum"
}

Custom

Each middleware is implementing the IMiddleware interface, which requires the alter(...) method to be implemented.

alter(request: http.IncomingMessage, response: http.ServerResponse): boolean;

All middlewares is required to return a boolean value. If a middleware is returning false, the request will stop executing.

import {IMiddleware} from 'fuhttp';

class MyCustomMiddleware implements IMiddleware {
    public alter(req, res): boolean {
        ... // Do some tweaks on the req / res objects here
        return true; // return false if you want to stop execution
    }
}

Examples

Multiple examples are found in the examples/ folder.

var fuhttp=require('fuhttp-ts'); // Load package

var myRoute = new fuhttp.Route();

myRoute.get("hello/:name", function(req, res, name) {
    res.write("Hello, your name is " + name);
    res.end();
});

var server = new fuhttp.Server(5000); // Defined the port number which the http-server should accept connections

server.add("api", myRoute); // Add the myRoute for parsing request URIs and call appropriate route
server.listen(); // Start listening for incoming requests

TODOs

  • [ ] ~~Support for connect middlewares~~
    • As the connect middlewares expectes an input parameter next() this idea was scrapped, as I'm not a fan of this design structure
  • [ ] Test middlewares?
  • [ ] Performance testing, and comparison of other libraries

Release History

See the changelog

License

© Fosen-Utvikling AS, 2016 - 2018. Licensed under a MIT license