1.0.4 • Published 2 months ago

hono-lite v1.0.4

Weekly downloads
-
License
ISC
Repository
gitlab
Last release
2 months ago

HonoLite

A lightweight Typescript wrapper around Hono. Get started with building secure APIs

Basic usage

The key features are:

  • simplicity
  • simplicity
  • and yes... simplicity

Create a server

Create a basic server:

import { HonoLite } from 'hono-lite';
const server = new HonoLite(PORT);

or with API key for security:

import { HonoLite } from 'hono-lite';
const server = new HonoLite(PORT, {
    apiKeyValue: '....secret-api-key-goes-here....',
});

Want routes to share immutable objects? Easy:

import {HonoLite} from "hono-lite";

const db = new SomeSQLConnector(...);
const redis = new RedisConnector(...);
const extras = {db, redis}; // <-- these will now be delivered to every route callback

const server = new HonoLite(PORT, {
  apiKeyValue: "....secret-api-key-goes-here...."
}, extras);

Returning valid responses (200 OK 👍)

Just return an object (like you normally do!):

server.Get('/fetch-some-obj', (cxt, extras) => {
    //... do something here ...
    return {
        status: 'ok',
        meta: extras['key'],
    };
});

Return error responses (5xx, 4xx, Xxx ⚠️)

Just throw an instance of ErrorLite; just give it an id and a body:

throw new ErrorLite('schema_validation_error', "'input' must be a valid string"); //default status 500

Want something richer or with a custom status code in the error? Do this:

throw new ErrorLite(
    'auth_error',
    {
        message: 'unauthorized access',
        someKey: '... more metadata ...',
    },
    401,
);

API keys made easy

API servers, need API keys :) Easy peasy:

const server = new HonoLite(
    PORT,
    { apiKeyValue: API_KEY }, // <--- checked against "x-api-key" req header by default
);

Want a custom request header? Do this:

const server = new HonoLite(PORT, {
    apiKeyValue: API_KEY,
    apiKeyHeader: 'my-custom-header',
});

Use classic Hono (if you really need to 🤷)

For instance, if you need to define custom middleware, good ol' Hono-style, do this:

server.use(async (_, next) => {
    //... do something ...
    await next();
});

Want to handle 404s differently, do this:

server.notFound((cxt) => {
    return cxt.json({ message: "can't find what you're looking for" }, 404);
});

The server is basically an extended instance of Hono.


Complete HonoLite Server example

Here's a basic server built using HonoLite.

import { HonoLite, ErrorLite } from 'hono-lite';

// define port, API key is optional
const PORT = 15000;
const API_KEY = 'some-api-key-goes-in-here';

// any object can be sent into the server as an "extra"
// and retrieved later inside the scope of a route callback
const xtra = {
    key: 'some-stock-value',
    db: 'could-be-an-object-too',
};

// instantiate the server with all these parameters
const server = new HonoLite(PORT, { apiKeyValue: API_KEY }, xtra);

// define a GET route
// each route could also be its own module that exports
// the callback function
server.Get('/posts/:id', (cxt, extras) => {
    const { id = '' } = cxt.req.param();
    //... do something here ...
    return {
        message: `You wanted id: ${id}`,
        meta: extras.db,
    };
});

// define a POST route that is secured using an API key
// the API key must be found in the 'x-api-key' req header
server.Post(
    '/do-some-thing-securely',
    async (cxt) => {
        // read the request body, reject if malformed
        const body = await cxt.req.json().catch(() => {
            throw new ErrorLite('invalid_body', 'request body was malformed');
        });

        // extract input data from the body
        // validate its schema
        const { input = '' } = body;

        if (typeof input === typeof '' && input.trim().length > 0) {
            //... do something ...
            return {
                status: 'success',
                meta: `You sent: ${input}`,
            };
        } else
            throw new ErrorLite('schema_validation_error', {
                message: "'input' must be a valid string",
            });
    },
    { useApiKey: true },
);

// start the server, log success message
server
    .start()
    .then((port) => console.log(`Server is running on port: ${port}`))
    .catch((reason) => server.close(() => console.log(reason)));

// cleanup before exit
const cleanup = () => server.close(() => console.log('Server closed'));
process.on('exit', cleanup);
process.on('SIGINT', cleanup);