Skip to content

Instantly share code, notes, and snippets.

@andywer
Last active February 27, 2019 12:57
Show Gist options
  • Select an option

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

Select an option

Save andywer/ffcbb910f19949636109d3cb9856e48d to your computer and use it in GitHub Desktop.
Sample usage - Better HAL package for node
import Koa from "koa"
import * as KoaHAL from "$new-hal-koa-package"
import { api, Users } from "./hal"
const app = new Koa()
const koaRouter = KoaHAL.Router(api, router => {
// GET /users
router.get(Users, async ctx => {
const users = await queryAllUsers()
ctx.body = Users(users).toObject()
// or just:
// return Users(users)
})
// ...
})
app.get("/", ctx => {
ctx.body = {
name: "My Demo API",
_links: api.Links({
self: "/",
users: api.routeTo(Users)
})
}
})
app.use(koaRouter.allowedMethods())
app.use(koaRouter.routes())
import * as HAL from "$new-hal-package"
interface OrderRecord {
id: string,
items: [],
customer_id: string,
created_at: Date
}
interface UserRecord {
id: string,
name: string,
created_at: Date
}
const router = HAL.Router(routes => {
// Needs to work both ways: Resolve resource instances to paths & define the paths to serve
routes.add(Order, "/orders/:id", order => ({ id: order.id }))
// same as:
routes.add(Order, "/orders/:id")
routes.add(User, "/users/:id")
routes.add(Users, "/users{?limit,offset,total}", (users: Users) => ({
limit: users.limit,
offset: users.offset,
total: users.total
}))
})
export const api = HAL.API("https://my-project.com/", router)
export function Order(record: OrderRecord) {
const resource = api.Resource(Order, record)
// same as:
// const resource = HAL.Resource(`/orders/${record.id}`, record)
// or:
// const resource = HAL.Resource(api.routeTo(Order, record), record)
return HAL.addLinks(resource, {
customer: api.routeTo(User, record.customer_id)
})
}
export function User(record: UserRecord) {
return api.Resource(User, record)
}
export function Users(
records: UserRecord[],
meta: { limit?: number, offset?: number, total?: number } = {},
links: { prev?: string, next?: string} = {}
) {
const resource = api.Collection(Users, records, meta)
// same as:
// const resource = HAL.embed(api.Resource(Users, meta), { records })
return HAL.addLinks(resource, links)
}
@andywer
Copy link
Author

andywer commented Feb 27, 2019

Alternative Koa HAL routes:

import * as KoaHAL from "$new-hal-koa-package"
import { api, Users } from "./hal"

const routes = {
  users: KoaHAL.ResourceRouter(api, Users)
}

routes.users.get(async ctx => {
  return Users(users)
})

const koaRouter = KoaHAL.Router(api, [
  routes.users
])

Benefit: Instead of having a source file for routes and one for the HAL resources, we can now also co-locate HAL stuff and route handling per resource (users.ts, orders.ts, ...)

@andywer
Copy link
Author

andywer commented Feb 27, 2019

Still need to solve: Resource constructors (User, Users, ...) require api and api requires them...

Shouldn't be hard to solve, though, since api needs references to the resources right away, but the resource constructors use api only when called.

Update: Solution

export function Order(record: OrderRecord) {
  const resource = api.Resource(Order, record)
  return HAL.addLinks(resource, {
-   customer: api.routeTo(User, record.customer_id)
+   customer: HAL.LinkTo(User, record.customer_id)
  })
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment