Skip to content

Lifecycle

Mapl request lifecycle can be illustrated as follows:

Lifecycle

Middlewares

Middlewares are functions that get executed on every request, after the route matching phase.

app.apply((c) => {
c.headers.push(['Server', 'Mapl']);
});

The above snippet adds the Server header to every response if the request path matched any of the defined patterns.

Note that middlewares share the same limitation as handlers, as if a middleware function returns a Promise object it must be marked as an async function.

Setters

Setter is a type of middleware that its returned value will be attached to the Context object.

// 'c.date' is now the current date
app.set('date', () => new Date());

The value can be used in any handler or middleware after it:

// Chaining should be used so you get type hint
app
.set('date', () => new Date())
.get('/time', (c) => `Current time: ${c.date.toUTCString()}`);

Errors

Mapl uses a much lighter and faster error implementation based on safe-throw.

To handle exceptions, use app.err:

import * as st from 'safe-throw';
// Error type is inferred based on previous middlewares
app.err((error, c) => {
c.status = 400;
return st.payload(error);
});

Exceptions are meant to be used with validators and parsers to handle edge cases.

Validators

Validator is a type of middleware to validate requests.

import * as st from 'safe-throw';
const bodyTooShort = st.err('Body too short');
app.check(async (c) => {
const body = await c.req.text();
if (body.length < 9)
return bodyTooShort;
});

If an exception is returned, the correct exception handler will be called.

If no exception handler is registered for that error (including the handler for all exceptions), a 400 Bad Request response will be returned.

Parsers

Parsers can return exceptions like validators, but if the return value is anything other than an exception it gets attached to the context.

const invalidAuthHeader = st.err('Invalid Authorization header');
// Chaining should be used so you get type hint
app
.parse('token', (c) => {
const authHeader = c.req.headers.get('authorization');
// Get the bearer token
return authHeader === null || !authHeader.startsWith('Bearer ')
? invalidAuthHeader
// Return the value to be attached to the context
: authHeader.slice(7);
})
.get('/', (c) => `Your token: ${c.token}`)
// Handle returned errors
.err((error, c) => {
c.status = 403;
// Return the text of the error
return st.payload(error);
});