UNPKG

@node-scarlet/http

Version:

Build APIs Instantly 🏋️‍♂️

122 lines (101 loc) 5.14 kB
# Build APIs Instantly 🏋️‍♂️ Serve [HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages) 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! ```javascript 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](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) the route will apply to. You can use strings like `"GET"`, or you can reference them from `http.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](https://www.npmjs.com/package/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` or `object` as a return type * Use `http.response()` to have richer control over the [status](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status), [headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers), and [body](https://en.wikipedia.org/wiki/HTTP_message_body). ```javascript // 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 a `params` 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`. ```javascript // 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. ```javascript 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": ```javascript 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); } } ```