Skip to content

Instantly share code, notes, and snippets.

@andywer
Last active November 19, 2018 09:29
Show Gist options
  • Select an option

  • Save andywer/4e6ce06c782874f05aa983a8d7bc96f8 to your computer and use it in GitHub Desktop.

Select an option

Save andywer/4e6ce06c782874f05aa983a8d7bc96f8 to your computer and use it in GitHub Desktop.
Better node server API - An attempt based on Koa
import { createApp, respond, route } from "koax"
import pkg from "../package.json"
const app = createApp()
app.get("/", async () => {
const body = {
name: pkg.name,
version: pkg.version
}
return respond(body, {
status: 200,
headers: {}
})
})
////////////////////////
// Low-level equivalent
app.use(route("GET", "/", async () => {
return respond("{}", {
status: 200,
headers: {
"Content-Length": 2,
"Content-Type": "application/json"
},
body: "{}"
})
}))
/**
* Concept of server framework:
* - Instead of passing request and mutable response,
* pass request into handler which returns the response
* - Can throw a response as an error escape-hatch
* - Here the alternative server framework API is a separate package
* - But could just be implemented as a Koa middleware
*
* Concept of route file:
* - Little code per route in router file to easily get an overview over routes
* - Take path params out of request and pass explicitly to keep path & params in one place
*
* Benefits:
* - No need to pass Koa context to route handlers, containing all kinds of stuff and util methods
* - Route handler only needs the request object, path params and the static `respond()` function import
* - HTTP-aware error handling all goes in route handler files
*/
import { createApp, respond } from "koax"
import config from "./config"
import { queryPostByID } from "./database"
const app = createApp()
app.get("/posts/:id", async ({ params, request }) =>
// Keep everything path-related together in this file
getPostByID(params.id, request.query, new URL("/posts/:id", config.baseURL))
)
///////////////////////////////////////////////
// Route handler, can be put in separate file:
async function getPostByID(id: string, query: { ignoreLegacy?: boolean }, href: string) {
const post = await queryPostByID(id, query)
if (!post) {
return respond(404, `Post not found: ${id}`)
// You can also throw a response:
// (remotely inspired by how React suspense does it in the frontend)
throw respond(404, `Post not found: ${id}`)
}
const body = {
_links: {
self: { href }
},
...post
}
return respond(body)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment