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

http-server-simple

v2.0.5

Published

http-server-simple is an http server written in pure javascript for NodeJS. It has no dependencies. The syntaxe was inspired by the Express library.

Downloads

10

Readme

http-server-simple is an http server written in pure javascript for NodeJS. It has no dependencies. The syntaxe was inspired by the Express library.

The following methods are supported: GET, HEAD, OPTIONS, POST, PUT, PATCH, DELETE.

Usage

const {Server} = require("http-server-simple");
const server = new Server();

/* GET 127.0.0.1:5000/text */
server.get("/text", (req,res) => {
    return res.text("Sending a text/plain message");
})
/* GET 127.0.0.1:5000/json */
.get("/json", (req,res) => {
    return res.json({message: "Sending an application/json message"});
})
/* GET 127.0.0.1:5000/html */
.get("/html", (req,res) => {
    return res.html("<h1>Sending a text/html message</h1>");
})
/* POST 127.0.0.1:5000/ */
.post("/", (req,res) => {
    return res.text("A post request to /");
})
.listen(5000, "127.0.0.1");

Router

Server level routing done in the previous example will implicitly create a router with the "/" root, you can create your own router with a different root


const {Server, Router} = require("http-server-simple");
const server = new Server();
const router = new Router();
const users = require("./data/users");

/* GET 127.0.0.1:5000/user */
router.get("/", (req,res) => {
    return res.json(users);
})
/* GET 127.0.0.1:5000/user/:id */
.get("/:id", (req,res) => {
    const id = req.params.id;
    return res.json(user.id);
})
/* DELETE 127.0.0.1:5000/user/:id */
.delete("/:id", (req,res) => {
    const id = req.params.id;
    delete user.id;
    return res.end();
});

server.router("/user",router).listen(5000,"127.0.0.1");

Router prefix

In order to create routes within the router with the same prefix without having to repeat the prefix in each route, you can use Router.prefix()

const {Server, Router} = require("http-server-simple");
const server = new Server();
const router = new Router();
const users = require("./data/users");
const posts = require("./data/posts");

const userRouter = Router.prefix("/user", router => {
    /* GET 127.0.0.1:5000/api/v1/user */
    router.get("/", (req,res) => res.json(users))

    /* GET 127.0.0.1:5000/api/v1/user/:id */
    .get("/:id", (req,res) => res.json(users[req.params.id]));
});

const postRouter = Router.prefix("/post", router => {
    /* GET 127.0.0.1:5000/api/v1/post */
    router.get("/", (req,res) => res.json(posts))

    /* GET 127.0.0.1:5000/api/v1/post/:id */
    .get("/:id", (req,res) => res.json(posts[req.params.id]));
});


server.router("/api/v1",[userRouter, postRouter])
    .listen(5000,"127.0.0.1");

Middleware

Route handlers are considered middlewares too. The only difference between a middleware and a handler is the use of the next function. Handlers do not use the next function, middlewares do. Not calling next in the middle of the middleware chain will hang the server. To exit a middleware chain you have to return res.text(), res.html(), res.json() or res.end()


const {Server, Router} = require("http-server-simple");
const server = new Server();
const router = new Router();

server.router("/router",router,(req,res,next) => {
    console.log("Router middlewares will execute before routes middlewares.");
    next();
}).listen(5000,"127.0.0.1");

/* 127.0.0.1:5000/router/get */
router.get("/get",
(req,res,next) => {
    console.log("Route middlewares execute after the router middlewares.");

    if(Math.random() < 0.5) {
        console.log("Call the next middleware.");
        return next();
    } 

    console.log("Otherwise terminate the chain.");
    return res.end();
    
},
(req,res) => {
    console.log("This is the route handler, it's last in the middleware chain and doesn't use the next function.");
    return res.end();
});

/* GET 127.0.0.1:5000/ */
server.get("/", (req,res,next) => {
    console.log("Server level routing also supports middlewares.");
    next();
},
(req,res) => {
    console.log("End of the chain = route handler.");
    return res.end();
});

Query Parameters

Use the req.query function to get the query parameters from the url


const {Server} = require("http-server-simple");
const server = new Server();

/* GET 127.0.0.1:5000/?a=1&b=2 */
server.get("/", (req,res) => {
    const queries = req.query(); // returns {a: "1", b: "2"}
    const a = req.query("a"); //returns "1"
    const c = req.query("c"); //returns null
    return res.end();
})
.listen(5000,"127.0.0.1");

Route parameters

Access the dictionary of route parameters with the req.params attribute


const {Server} = require("http-server-simple");
const server = new Server();

/* GET 127.0.0.1:5000/user/:id */
server.get("/user/:id", (req,res) => {
    const id = req.params.id;

    return res.html(`<h1>This is user ${id}</h1>`);
})
.listen(5000,"127.0.0.1");

Body parsing

Access the body of a POST,PUT or PATCH request with req.body. The body will be parsed depending on the Content-Type header. If the parsing failed, the Content-Type is invalid or no Content-Type was specified, req.body will be the raw data with the specified encoding.

For all other methods, req.body returns undefined

SERVER SIDE

const {Server} = require("http-server-simple");
const server = new Server();
const users = require("./data/users");

/* PUT 127.0.0.1:5000/user/:id */
server.put("/user/:id", (req,res) => {
    const id = req.params.id;

    // {name: "bob", age: 10}
    const newData = req.body;

    users[id] = {...users[id], ...newData};

    return res.json(users[id]);
})
.listen(5000,"127.0.0.1");

CLIENT SIDE (using urlencoded)

fetch("http://127.0.0.1:5000/user/1", {
    method: "PUT",
    body: "name=bob&age=10",
    headers: {
        "Content-Type": "application/x-www-form-urlencoded"
    }
});

Unhandled exceptions

A status code 500 and no content will be sent as a response if an uncaught exception happens in one of the middlewares or handlers

SERVER SIDE

const {Server} = require("http-server-simple");
const server = new Server();

/* PUT 127.0.0.1:5000/exception */
server.get("/exception", (req,res) => {
    res.nonExistantFunction();
})
.listen(5000,"127.0.0.1");

CLIENT SIDE

const res = await fetch("http://127.0.0.1:5000/exception");

//true
console.log(res.status === 500);

Download

Downloading a file from the disk can be done in two ways. the "low level" way is with the res.download method and the "high level" way is with the Download class helper.

res.download takes as argument a File object and, optionally, an object containing the start and end bytes that you would like to download.

SERVER SIDE

const {Server, File} = require("http-server-simple");
const server = new Server();

/* PUT 127.0.0.1:5000/download */
server.get("/download", (req,res) => {
    //content of file: 0123456789
    const file = new File("path/to/a/file/that/exists");

    opts = {};
    if(req.query("start")) {
        opts.start = parseInt(req.query("start"));
    }
    if(req.query("end")) {
        opts.end = parseInt(req.query("end"));
    }

    return res.download(file, opts);
})
.listen(5000,"127.0.0.1");

CLIENT SIDE

let res = await fetch("http://127.0.0.1:5000/download");
let text = await res.text();

//0123456789, or it will download the file on a browser that respect the Content-Disposition header
console.log(text);
console.log(res.status); //200

res = await fetch("http://127.0.0.1:5000/download?start=2");
text = await res.text();

console.log(text); //23456789
console.log(res.status); //206

res = await fetch("http://127.0.0.1:5000/download?end=5");
text = await res.text();

console.log(text); //012345
console.log(res.status); //206

res = await fetch("http://127.0.0.1:5000/download?start=2&end=5");
text = await res.text();

console.log(text); //23456
console.log(res.status); //206

res = await fetch("http://127.0.0.1:5000/download?start=100");

//416, invalid range
console.log(res.status);

the Download class however only takes a File object or a string representing its path as argument. It looks at the Range header to determine what bytes to send.

SERVER SIDE

const {Server, Download} = require("http-server-simple");
const server = new Server();

/* PUT 127.0.0.1:5000/download */
server.get("/download", (req,res) => {
    //content of file: 0123456789
    const file = "path/to/a/file/that/exists";
    const downloader = new Download(req,res);

    return downloader.download(file);
})
.get("/resumableDownload", (req,res) => {
    const file = "path/to/a/file/that/exists";
    const downloader = new Download(req,res);

    return downloader.resumableDownload(file);
})
.listen(5000,"127.0.0.1");

CLIENT SIDE

let res = await fetch("http://127.0.0.1:5000/download");
let text = await res.text();

console.log(text); //0123456789
console.log(res.status); //200

res = await fetch("http://127.0.0.1:5000/download", {
    headers: {
        "Range": "bytes=2-"
    }
});
text = await res.text();

 //0123456789, the Range header was ignored because downloader.download() does not support resuming therefore it downloads the whole file.
console.log(text);
console.log(res.status); //200

res = await fetch("http://127.0.0.1:5000/resumableDownload", {
    headers: {
        "Range": "bytes=2-"
    }
});
text = await res.text();

console.log(text); //23456789
console.log(res.status) //206