Stone.jsDocs
Paradigm

Routing

Model binding

A route parameter is usually an id, and the handler's first act is to look up the thing that id points to. Binding moves that lookup to the route, so the handler receives the resolved model directly and stays about behaviour, not plumbing.

#Resolve at the boundary

The principle

Every handler repeating "take the id, fetch the entity, handle the not-found case" is boilerplate at the boundary. Lift it to the route definition once, and each handler starts from a real object.

In Stone.js

The bindings option maps a parameter to a resolver: a function that receives the raw value and the container, and returns the model. The resolved value replaces the raw parameter on the event.

app/Tasks.tsdeclarativeimperative
import { Get, EventHandler } from '@stone-js/router'
import { IncomingHttpEvent } from '@stone-js/http-core'

@EventHandler('/tasks')
export class TaskController {
  constructor ({ tasks }: { tasks: TaskService }) { this.tasks = tasks }

  // Resolve the :id param into a Task before the handler runs.
  @Get('/:id', {
    bindings: { id: (value, { container }) => container.resolve('tasks').find(value) }
  })
  show (event: IncomingHttpEvent) {
    const task = event.get<Task>('id')   // already the resolved Task, not the raw id
    return task
  }
}
import { defineEventHandler, defineRoutes } from '@stone-js/router'

export const routes = defineRoutes([
  [defineEventHandler(TaskController, 'show'), {
    path: '/tasks/:id',
    method: 'GET',
    bindings: { id: (value, { container }) => container.resolve('tasks').find(value) }
  }]
])

#Reusable binding resolvers

A resolver is just a function, so factor common ones out and share them across routes. A binding can also be a bound-model descriptor when a type always resolves the same way.

app/bindings.tsts
export const bindTask = (value, { container }) => {
  const task = container.resolve('tasks').find(value)
  if (task === undefined) throw new RuntimeError('Task not found')  // 404 at the edge
  return task
}

// then: @Get('/:id', { bindings: { id: bindTask } })

Stone.js

Your app exists in every runtime. Until you run it.

An open-source project by Stone Foundation
Created by Mr. Stone (Evens Pierre)