Skip to main content

REST API Routing

App routes lets you create secure public (REST) API endpoints to serverless JavaScript functions in your application.

Example REST API route

The example app routes below creates two REST API endpoint routes that triggers a serverless function. This simple example function echo does nothing useful, other than echoing back the request data to the client as JSON.

index.js
import app from 'codehooks-js'

// Codehooks API routes
app.post('/myroute', echo);
app.get('/myroute/:var1/:var2', echo);

// Serverless function
function echo(req, res) {
res.json(req);
}

// bind to Codehooks runtime
export default app.init();

After deploying the REST API with the coho deploy CLI command we can run a quick test from the command line using curl.

tip

You can use Postman together with Codehooks for testing your APIs.

Example command line
curl https://myproject-abcd.api.codehooks.io/dev/myroute/123/321
-H 'x-apikey: 6e111ea6-6b3a-412d-8f6b-061c816c67c9'

The example shows that our function echoes back the input as a structured (and very handy) JSON object.

Example output

{
"hostname": "myproject-abcd.api.codehooks.io",
"headers": {
"host": "myproject-abcd.api.codehooks.io",
"user-agent": "curl/7.77.0",
"accept": "*/*",
"x-apikey": "6e111ea6-6b3a-412d-8f6b-061c816c67c8"
},
"query": {},
"path": "/dev/myroute/123/321",
"apiPath": "/myroute/123/321",
"originalUrl": "/dev/myroute/123/321",
"params": {
"var1": "123",
"var2": "321"
},
"body": {},
"method": "GET"
}

After deployment the specified routes will be available as HTTPS endpoints.

REST API endpoint URL spec

A REST API app route is available at an HTTPS endpoint based on the HTTP verb, tenant ID, datastore name and API route specification.

            ┌─── Project Id, e.g. booking-2b39
│ ┌─── Project space name (environment) , e.g. prod
│ │ ┌─── API route, e.g. /cars/:model/:make
│ │ │ ┌─── Parameters, e.g. color=black
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
https://<PROJECT>.api.codehooks.io/<SPACE>/<API-ROUTE>[?QUERY]

Example URL: /cars/:model/:make

https://booking-2b39.api.codehooks.io/prod/cars/Tesla/model-x?color=black&campaign=A

REST API route matching

Any request agaist a space REST API, e.g. /dev/*, are matched against the deployed and declared app route functions.

String path

Route declaration must match exact to trigger function.

// matches: https://apollo-ff00.api.codehooks.io/dev/admin
app.get("/admin", myFunc)

Path parameters

Route declaration can match variable named segments of route to trigger function.

// matches: https://apollo-ff00.api.codehooks.io/dev/admin/abc-123
app.get('/admin/:messageId', myFunc)

Wildcard

Route declaration can match wildcard segments of route to trigger function.

// matches: https://apollo-ff00.api.codehooks.io/dev/user/abc-123/inbox
// matches: https://apollo-ff00.api.codehooks.io/dev/user/turbo-xyz/inbox
app.get('/user/*/inbox', myFunc)

Regular expression

Route declaration matches a regular expression to trigger function.

// matches: https://apollo-ff00.api.codehooks.io/dev/foo/bar
// matches: https://apollo-ff00.api.codehooks.io/dev/user/bar/foo/y/x
app.get(/^\/(foo|bar)/, myFunc)

The REST API request object

The request object contains these following properties for a client (HTTPS) request.

  • request.headers
  • request.query
  • request.params
  • request.body
  • request.path
  • request.apipath
  • request.originalUrl
  • request.method
  • request.hostname
  • request.pipe(...)
  • request.on(...)

request.headers

Get the HTTP header values as key-value pairs.

console.log(req.headers['user-agent']); // -> PostmanRuntime/7.29.0

request.query

Get the URL query parameters as key-value pairs.

// route: /product
// url : /dev/product?price=10
console.log(req.query.price); // -> 10

request.params

Get the URL route variables as key-value pairs.

// route: /order/:orderID/:type
// url : /dev/order/12345/small
console.log(req.params.orderID, req.params.type); // -> 12345, small

request.body

Get the request body.

console.log(req.body); // -> {"foo": "bar"}

request.path

Get the URL full path.

// route: /order/:orderID
// url : /dev/order/12345
console.log(req.path); // -> /dev/order/12345

request.apipath

Get the URL api path.

// route: /order/:orderID
// url : /dev/order/12345
console.log(req.apipath); // -> /order/12345

request.originalUrl

Get the URL full path and query parameter string.

// route: /order/:orderID
// url : /dev/product?size=small
console.log(req.originalUrl); // -> /dev/product?size=small

request.method

Get the HTTP request verb.

// url: /dev/product
console.log(req.method); // -> GET

request.hostname

Get the project URL domain name.

// url: https://myproject-ff00.api.codehooks.io/dev/product
console.log(req.hostname); // -> myproject-ff00.api.codehooks.io

request.pipe(Stream)

Process a request data stream by piping it to another stream. Useful to process other data formats than JSON, e.g. binary or raw data content types - content-type: application/octet-stream.

const mystream = new PassThrough();
// process mystream
req.pipe(mystream);

request.on(event, data)

Process a request data stream by listening to the request data emitter. Useful to process other data formats than JSON, e.g. binary or raw data content types - content-type: application/octet-stream.

req.on('data', (buf) => {
console.log(buf.length) // process buf data
})
req.on('end', (bytes) => {
console.log('Got binary data', bytes)
res.end('Got binary ' + bytes)
})

The REST API response object

The response object sends data back to the client and finalizes the request.

response.set(header, value)

Set a response header value.

Parameters

Code example

function myFunc(req, res) {
res.set('Content-Type', 'text/html; charset=UTF-8'); // set a response header
res.end('<h1>Hello world!</h1>'); // send html back to client
}

response.headers(Object)

Set multiple response header values.

Parameters

Code example

function myFunc(req, res) {
res.headers({
'Content-Type': 'text/html; charset=UTF-8',
'X-myheader': '123456890'
});
res.send('<h1>Hello world!</h1>'); // send html back to client
}

response.status(HttpStatusCode)

Return a HTTP response status code for a client request.

Parameters

Code example

function myFunc(req, res) {
res.status(401); // Unauthorized
res.end();
}

response.json(Object)

Return a JSON response for a client request.

caution

Ends the client request and terminates the Codehook execution.

Parameters

  • Object JSON

Code example

function myFunc(req, res) {
res.json({"message": "Hello"});
}

response.write(data, [encoding])

Stream data back to the client as text or binary data buffers.

NB! content-type must be set before any write operations.

Parameters

  • data string or any data that the Content-Type allows
  • encoding optional string use res.write(mybuf, 'buffer') to write binary data back to client

Code example

async function myFunc(req, res) {
res.set('content-type', 'text/plain');
res.write('Hello');
res.write('world!')
res.write('\n');
res.end();
}

response.send(data)

End response for a client request.

caution

Ends client request and terminates the Codehook execution immediately.

If not called, the Codehook will not return and finally time out.

Parameters

  • data string

Code example

function myFunc(req, res) {
res.send("Thanks for visiting!");
res.end();
}

response.end()

End response for a client request.

caution

Ends client request and terminates the Codehook execution immediately.

If not called, the Codehook will not return and finally time out.

Parameters

  • none

Code example

function myFunc(req, res) {
res.send("Thanks for visiting!");
res.end();
}

response.writable

Get the Writable object that can be used in node.js Stream operations.

mystream.pipe(res.writable)

Middleware functions

You can create middleware logic by chaining functions in an array or globally with the app.use function. Each function have a next method parameter that is used to "chain" the next function or to terminate the chain. The example below shows how a middleware function is called before the main function. The middelware function typically check some state or logic before proceeding to the next.

index.js
import app from 'codehooks-js'

// Global middleware on all routes
app.use((req, res, next) => {
console.log("I'm global");
res.next();
})

// Global middleware on route matches
app.use('/my*', (req, res, next) => {
console.log("I'm global match for /my*");
res.next();
})

// Example route with middleware
app.post('/myroute', middleWare, myFunc);

function myFunc(req, res) {
// All is OK, got here finally
res.end();
}

function middleWare(req, res, next) {
let OK = true;
// do something here
if (OK) {
next();
} else {
res.status(401); // Unauthorized
res.end();
}
}

export default app.init();

Wildcard routes

Wildcards lets you match all methodsand all routes that are not matched by previous routes. See example code below.

index.js
import app from 'codehooks-js'

app.get('/myroute': getFunc);
app.put('/myroute/:id': putFunc);

// wildcard route
app.all('/*': (req, res) => {
res.end("I catch all methods, on all routes not matched before");
}
)

export default app.init();