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

spiel-server

v1.0.1

Published

Middleware framework to make easy to write backend applications

Readme

Spiel Server

Travis CI npm

Spiel server is a middleware framework to make easy create backend applications.

  • You can create easily endpoints with decorators and make more logic your code.
  • Spiel server creates automatically a root endpoint which response with all the endpoints and its methods of the backend application.
  • It uses Roads as core which make possible to attach the middlewares in HTTP servers like Koa.js, Express.js or use roads-server which is also integrate.

Api documentation

Example

How use it

Create your endpoints

Spiel server generates the url request for you according with the class and method name

import {Endpoint, Get, IUrl, Road, SetRouter} from "spiel-server";

@Endpoint()
class User {
    private body;

    @Before(info)
    @Get("")
    public getUsers() {
        return new Response(users, 200);
    }

    @Post("")
    public addUser(url: IUrl) {
        const user = this.body;
        users.push(user);
        return new Response(users, 200);
    }
}

Notice that you will have the body request already parsed in this.body if you want the body without parse (string) then you have to past body by argument like this:

@Endpoint()
class User {
    private body: any;

    @Post("")
    public addUser(url: IUrl, body) {
        console.log(body);
        const user = this.body;
        users.push(user);
        return new Response(users, 200);
    }
}

Create your middlewares

import {After, AfterAll, Before, BeforeAll, Delete, Endpoint, Get, HttpError,
    IRouterOptions, IUrl, middleware, Post, Put, Response,
    Road, Server, SetRouter} from "../src";
import {users} from "./assets";

const info = (method: string, path: string, body: any, headers: Headers, next: () => any) => {
    console.log(`A ${method} request was made to ${JSON.stringify(path)}`);
    return next();
};

const infoAll = (method: string, path: string, body: any, headers: Headers, next: () => any) => {
    console.log("The middleware start");
    return next();
};

const changeResponse = (method: string, path: string, body: any, headers: Headers, next: () => any) => {
    console.log("End");
    return next();
};

const finish = (method: string, path: string, body: any, headers: Headers, next: () => any) => {
    console.log("Finish");
    return new Response({greet: "Bye"}, 200);
};

@BeforeAll(infoAll)
@Endpoint()
class User {
    private body: any;

    @Before(info)
    @Get("", {name: "user", secret})
    public getUsers() {
        return new Response(users, 200);
    }
    @Get("#id")
    public getUser(url: IUrl) {
        const id = url.args.id;
        const user: any = users.find((elment) => elment.id === id);
        return new Response(user, 200);
    }

    @Post("", {name: "admin", secret})
    public addUser(url: IUrl) {
        const user = this.body;
        users.push(user);
        return new Response(users, 200);
    }

    @Put("#id", {name: "admin", secret})
    public updateUser(url: IUrl) {
        const id = url.args.id;
        const resp = users.map((user) => {
            const value = user;
            if (value.id === id) {
                value.permission = this.body.permission;
            }
            return value;
        });
        if (!resp) {
            return new HttpError("User not found", 404);
        } else {
            return new Response(resp, 200);
        }
    }

    @Delete("#id", {name: "admin", secret})
    public deleteUser(url: IUrl) {
        const id = url.args.id;
        const index = users.findIndex((user: any) => user.id === id);
        users.splice(index, 1);
        return new Response(users, 200);
    }
}

@Endpoint()
@AfterAll(finish)
class Greeting {
    @After(changeResponse)
    @Get("")
    public getGreeting(url: IUrl, body: any, headers: Headers, next: () => {}) {
        console.log("HELLO EVERYBODY");
        return next();
    }
}

@Endpoint()
class OtherClass {
    @Get("$name")
    public getName(url: IUrl, body: any, headers: Headers, next: () => {}) {
        return new Response(url.args, 200);
    }
}

Since the versoin 1.0 you don't need to write any path logic just put before/beforeAll/after/afterAll when you want the middleware execution.

Setting the router


const endpoints = [new User(), [new Greeting(), new OtherClass()]];

const cors = {
    validOrigins: ['http://localhost:8080'],
    responseHeaders: ['content-type']
};

const configRouter: IRouterOptions = {
  connectionMode: true,
  cors,
  endpoints,
  road: app,
  verbose: true,
};

new SetRouter(configRouter);

Notice that you can group the routers allowing more flexible project structure

Using the roads API

import {Road, middleware} from "spiel-server";

const app = new Road();

app.use(middleware.cors({
    validOrigins: ['http://localhost:8080'],
    responseHeaders: ['content-type']
}));

About the Roads Api see in Roads docs

AuthConnection

If you use Spiel Connect you can send the head authconnection with the token of permission array as value and Spiel Server only will response with the method that match with the permission sent. Example:

Send the token:

const permissions = ["admin", "user"];
secret = "7983ac7ab1f7f706a962f6679bbdaae9ede06519c75e1ae7f1f92f3474eae21d";
const token = jwt.encode(permissions, secret);
headers = {authconnection : token};

Add permission to method

@Endpoint()
class OtherClass {
    @Get("$name", {name: "admin", secret})
    public getName(url: IUrl, body: any, headers: Headers, next: () => {}) {
        return new Response(url.args, 200);
    }
}

Set authConnection and connectionMode true in router options

const configRouter: IRouterOptions = {
  authConnection: true,
  connectionMode: true,
  endpoints,
  road: app,
  verbose: true,
};

new SetRouter(configRouter);

Complete example with Server

import {After, AfterAll, Before, BeforeAll, Delete, Endpoint, Get, HttpError,
    IRouterOptions, IUrl, middleware, Post, Put, Response,
    Road, Server, SetRouter} from "../src";
import {users} from "./assets";

const app = new Road();
const secret = "7983ac7ab1f7f706a962f6679bbdaae9ede06519c75e1ae7f1f92f3474eae21d";

const server = new Server(app, (error: any) => {
    switch (error.code) {
        case 404:
            return new Response("Not Found", 404);
        case 405:
            return new Response("Not Allowed", 405);
        default:
        case 500:
            return new Response(error.message, 500);
    }
});

const info = (method: string, path: string, body: any, headers: Headers, next: () => any) => {
    console.log(`A ${method} request was made to ${JSON.stringify(path)}`);
    return next();
};

const infoAll = (method: string, path: string, body: any, headers: Headers, next: () => any) => {
    console.log("The middleware start");
    return next();
};

const changeResponse = (method: string, path: string, body: any, headers: Headers, next: () => any) => {
    console.log("End");
    return next();
};

const finish = (method: string, path: string, body: any, headers: Headers, next: () => any) => {
    console.log("Finish");
    return new Response({greet: "Bye"}, 200);
};

@BeforeAll(infoAll)
@Endpoint()
class User {
    private body: any;

    @Before(info)
    @Get("", {name: "user", secret})
    public getUsers() {
        return new Response(users, 200);
    }
    @Get("#id")
    public getUser(url: IUrl) {
        const id = url.args.id;
        const user: any = users.find((elment) => elment.id === id);
        return new Response(user, 200);
    }

    @Post("", {name: "admin", secret})
    public addUser(url: IUrl) {
        const user = this.body;
        users.push(user);
        return new Response(users, 200);
    }

    @Put("#id", {name: "admin", secret})
    public updateUser(url: IUrl) {
        const id = url.args.id;
        const resp = users.map((user) => {
            const value = user;
            if (value.id === id) {
                value.permission = this.body.permission;
            }
            return value;
        });
        if (!resp) {
            return new HttpError("User not found", 404);
        } else {
            return new Response(resp, 200);
        }
    }

    @Delete("#id", {name: "admin", secret})
    public deleteUser(url: IUrl) {
        const id = url.args.id;
        const index = users.findIndex((user: any) => user.id === id);
        users.splice(index, 1);
        return new Response(users, 200);
    }
}

@Endpoint()
@AfterAll(finish)
class Greeting {
    @After(changeResponse)
    @Get("")
    public getGreeting(url: IUrl, body: any, headers: Headers, next: () => {}) {
        console.log("HELLO EVERYBODY");
        return next();
    }
}

@Endpoint()
class OtherClass {
    @Get("$name")
    public getName(url: IUrl, body: any, headers: Headers, next: () => {}) {
        return new Response(url.args, 200);
    }
}

const endpoints = [new User(), [new Greeting(), new OtherClass()]];

const configRouter: IRouterOptions = {
  authConnection: true,
  connectionMode: true,
  endpoints,
  road: app,
  verbose: true,
};

new SetRouter(configRouter);

server.listen(3000, () => {
  console.log("Serve is running in the port 3000");
});

Config your project:

{
	"compilerOptions": {
		"module": "commonjs",
		"target": "es6",
		"strict": true,
		"sourceMap": true,
		"rootDir": ".",
		"experimentalDecorators": true,
		"emitDecoratorMetadata": true,
		"outDir": "./lib",
		"declaration": true
	},

	"include": [
		"src/index.ts"
	]
}

Run Spiel Server tests

npm test

License

Spiel Server is MIT licensed. See license