1.0.0 • Public • Published

Curveball Controller

This package provides a simple controller pattern for curveballjs applications.

It's usage in the Curveball framework is entrirely optional, but it makes designing resource-oriented API's easier.

Basic features

  • Handles all methods for a single route in an application.
  • Implements the OPTIONS method and returns all supported HTTP methods in an Allow header.
  • Automatically throws a 405 Method Not Allowed for unsupported methods.
  • Support for negotiating the Accept header.


npm install @curveball/controller

Getting started

To create a controller, subclass the main controller. HTTP methods are represented by methods on the class.

import Controller from '@curveball/controller';
import { Context } from '@curveball/core';

class MyController extends Controller {

  get(ctx: Context) {

    ctx.response.body = 'Hello world';



To use your controller, you probably want to use the @curveball/router package:

import { Application } from '@curveball/core';
import { router } from '@curveball/router';

const app = new Application();

  router('/hello-world', new MyController())

Differences from common frameworks

Every controller is responsible for exactly 1 route in your application. A controller is a ES6 class, and it's methods match HTTP methods.

This makes it slightly different from common controllers from many popular frameworks, where a single controller typically handles a 'group' of functionality with index, create, update, read and delete functions.

To model the same index, create, update, read, delete functions with this controller, you just need two controllers instead:

class Collection extends Controller {

  get(ctx: Context) {
    // index

  post(ctx: Context) {
    // create


class Item extends Controller {

  get(ctx: Context) {
    // read

  put(ctx: Context) {
    // update

  delete(ctx: Context) {
    // delete

And then to use them:

import { Application } from '@curveball/core';
import { router } from '@curveball/router';

const app = new Application();

  router('/articles', new Collection())
  router('/articles/:id', new Item())

Negotiating the Accept header

If you API supports multiple formats, for example json and html, you can use the @accept and @method annotations to automatically handle these.

import { Controller, method, accept } from '@curveball/controller';
import { Context } from '@curveball/core';

class MyFancyController extends Controller {

  getJson(ctx: Context) {

    ctx.response.type = 'application/json';
    ctx.response.body = { 'hello': 'world' };


  getHtml(ctx: Context) {

    ctx.response.type = 'text/html';
    ctx.response.body = '<h1>Hello world</h1>';



This controller uses the @method annotation to automatically route a HTTP method to a controller function.

If there was no match for the @accept annotation, the server will automatically throw 406 Not Acceptable.

It's possible to specify multiple @accept annotations. The @accept annotation contains a mimetype, but it's possible to only specify a part of the mimetype. For example, the following values for the @accept annotation will all match application/hal+json:

  • json
  • application/*
  • */json
  • application/json
  • application/hal+json
  • hal+json
  • application/hal+json; version=2

To make a specific function match any accept header, you can add an @accept('*') annotation

WebSocket Support

The Controller has built-in WebSocket support. Sample usage:

import { Controller } from '@curveball/controller';
import { Application, WsContext } from '@curveball/core';

class MyController extends Controller {

  webSocket(ctx: WsContext) {




const app = new Application();
app.use(new MyController());

// Listen on port 5000 for Websocket

Package Sidebar


npm i @curveball/controller

Weekly Downloads






Unpacked Size

29.1 kB

Total Files


Last publish


  • evrt
  • mihok
  • juhangsin
  • beckypollard