@node-scarlet/http v0.10.4
Build APIs Instantly 🏋️♂️
Serve HTTP in seconds with URL routing out of the box.
Down to business
The almost 👏 simplest possible example:
Run the program, and visit localhost:5000
in your browser to see things in action!
const http = require('@node-scarlet/http');
const { GET, POST } = http.methods;
const requests = http.server();
requests.route(GET, '/*', (req, meta) => 'Hello, World!');
requests.route(POST, '/json', (req, meta) => ({ success: true }));
requests.listen(5000);
Routing
requests.route()
always takes the same 3 parameters:
- method: The type of HTTP Method the route will apply to. You can use strings like
"GET"
, or you can reference them fromhttp.methods
as shown above. - urlpattern: A string that represents which URL paths the route will apply to. The syntax is based on the url-pattern format.
- handler: A function that determines how the route should respond to requests that it applies to.
Handler Functions
Request handler functions use req
and meta
to determine how to react to incoming requests. If they return a truthy value, that value will be used to respond.
- For simple responses, you can use a
string
orobject
as a return type - Use
http.response()
to have richer control over the status, headers, and body.
// handlers.js
// string/object shorthand
const saySomething = (req, meta) => 'Hello there!';
const getJson = (req, meta) => { message: 'anybody listening?' };
// full response syntax
const denyAccess = (req, meta) => {
return http.response({
status: 403,
headers: { 'content-type', 'text/html' },
body: '<h1>Access Denied</h1>'
})
}
Handler Arguments
req
The req
argument is short for "request", and has the following properties:
method
: The http verb (GET, POST, etc..) that the request was made with.headers
: An object containing header names, and their corresponding values.url
: The full url pathname starting after the domain, E.G:"/products/hats?id=45&limit=1"
.params
: An object representation of dynamic url segments. A request matching the url. pattern"/products/:type"
, might have aparams
value of{ type: "hats" }
, or{ type: "watches" }
.body
: A string representation of the request body.query
: An object representation of querystring values, E.G:{ id: "45", limit: 1 }
.
meta
meta
starts off as an empty object, but is intended to be populated with arbitary data that can be used by other handlers. Some handler won't return a response, but instead set properties of meta
to be used by downstream handlers. One such example might be a handler that authenticates a requester's identity, and stores their account data on meta
.
// handlers.js
const attachMeta = (req, meta) => {
meta.desire = req.query.emotion || 'love';
}
// Utilize the meta value set by attachMeta()
const emote = (req, meta) => {
return http.response({
status: 200,
headers: {},
body: 'Wilber didn\'t want food. He wanted ' + meta.desire,
})
}
Tying things together
For organization, you'll typically want to define your request handlers in their own module instead of inline.
const http = require('@node-scarlet/http');
const { GET, POST } = http.methods;
const handlers = require('./handlers');
const requests = http.server();
requests.route(GET, '/*', handlers.attachMeta);
requests.route(GET, '/greeting', handlers.saySomething);
requests.route(POST, '/secrets', handlers.denyAccess);
requests.route(GET, '/sad/story', handlers.emote);
requests.listen(5000);
Stopping Service
Stop listening for requests with requests.close()
.
Ports
Specify which networking port to listen over with requests.listen()
. If no port
argument is provided, a random available port will be chosen.
Once listening, requests.port()
will return the active port.
Static Files
"Static" refers to any file that you may want to serve to browsers outright, like .html
, .css
, or .js
.
In a production environment, Node should rely on a reverse-proxy like Nginx to serve static files, but for small projects or development environments, you can use something like the following.
Assuming the static file directory is called "public":
const { resolve, join } = require('path');
const { createReadStream } = require('fs');
/**
* Create a handler that will attempt to serve static files
* from a given directory path.
*
* USAGE:
* requests.route(GET, '/*', staticFiles(__dirname + "public"));
*/
export const staticFiles = path => {
return async req => {
const filepath = join(resolve(path), req.url);
if (filepath[filepath.length-1] != '/')
return createReadStream(filepath);
}
}