A middleware cascade implementation for Azure Functions JS 2.x (inspired by Koa and Express).
npm install azure-func-middleware --save
Method use
adds middleware handler to a cascade.
Middleware handlers are executed in the order they are added.
To go to the next middleware handler, use the next
callback.
Method listen
composes middlewares to the Azure Function handler.
const AzureFuncMiddleware = require('azure-func-middleware');
module.exports = new AzureFuncMiddleware()
.use(async (ctx, next) => {
// will be called first
// ...
next();
})
.use((ctx, next) => {
// will be called second if no error in first
// ...
ctx.done(null, { status: 200 });
})
.catch((err, ctx, next) => {
// will be called if there is error in first or second
// ...
ctx.done(null, { status: 500 });
})
.listen();
To complete the response process, use done
callback of the context object
function.json
{
"bindings": [
...
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
index.js
const AzureFuncMiddleware = require('azure-func-middleware');
module.exports = new AzureFuncMiddleware()
.use((ctx) => {
const response = {
status: 200,
body: 'OK'
};
ctx.done(null, response);
})
.listen();
function.json
{
"bindings": [
...
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
index.js
const AzureFuncMiddleware = require('azure-func-middleware');
module.exports = new AzureFuncMiddleware()
.use((ctx) => {
ctx.res = {
status: 200,
body: 'OK'
};
ctx.done();
})
.listen();
If an error is thrown in the middleware handler, then the nearest error middleware handler is called.
Error handlers are added by the catch
method.
const AzureFuncMiddleware = require('azure-func-middleware');
module.exports = new AzureFuncMiddleware()
.use((ctx, next) => {
throw new Error('Error!'); // or next(new Error('Error!'));
})
.use(async (ctx, next) => {
// won't be called
// ...
next()
})
.catch((err, ctx, next) => {
// will be called
ctx.done(null, {
status: 500,
body: err.message // 'Error!'
});
})
.listen();
For passing data through middlewares you can use namespace state
of the context object
const AzureFuncMiddleware = require('azure-func-middleware');
module.exports = new AzureFuncMiddleware()
.use(async (ctx, next) => {
ctx.state.count = 1;
next();
})
.use((ctx, next) => {
ctx.state.count += 1; // ctx.state.count === 2
ctx.done(null, { status: 200 });
})
.listen();
The method useIf
adds a middleware handler that will be executed if the predicate
returns true.
const AzureFuncMiddleware = require('azure-func-middleware');
module.exports = new AzureFuncMiddleware()
.useIf(ctx => ctx.req.method === 'HEAD', (ctx, next) => {
// will be called if HEAD request
// ...
})
.useIf(ctx => ctx.req.method === 'GET', (ctx, next) => {
// will be called if GET request
// ...
})
.listen();
Often Azure Functions use a common sequence of middlewares.
You can declare this sequence and add using the method useMany
.
common.js
const defineUser = (ctx, next) => {
//...
};
const checkRoles = (ctx, next) => {
//...
};
module.exports = [
defineUser,
checkRoles
]
index.js
const AzureFuncMiddleware = require('azure-func-middleware');
const common = require('common');
module.exports = new AzureFuncMiddleware()
.useMany(common)
.use((ctx, next) => {
// will be called after common
})
.listen();
The Azure Function handler returns a promise. This fact can be used for testing.
function.json
{
"bindings": [
...
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
test.js
const funcHandler = require(...);
it('should work', async () => {
const context = { ... };
const expectedBody = ...;
const { status, body } = await funcHandler(context);
expect(status).toEqual(200);
expect(body).toEqual(expectedBody);
});
function.json
{
"bindings": [
...
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
test.js
const funcHandler = require(...);
it('should work', async () => {
const context = { ... };
const expectedBody = ...;
await funcHandler(context);
expect(context.res.status).toEqual(200);
expect(context.res.body).toEqual(expectedBody);
});
Add a middleware to a cascade
Add a middleware with condition to a cascade
predicate
predicatefn
middlewareHandler
Add several middlewares to a cascade
fns
Array<(errMiddlewareHandler | middlewareHandler)>
Add several middlewares to a cascade with condition
predicate
fns
Array<(errMiddlewareHandler | middlewareHandler)>
Add a middleware for error handling to a cascade
Add a middleware for error handling with condition to a cascade
predicate
fn
errMiddlewareHandler
Compose middlewares to a function handler
Returns funcHandler
Type: Function
context
Object The context object
Returns Promise
Type: Function
context
Object The context objectnext
next
Type: Function
error
Errorcontext
Object The context objectnext
next
Type: Function
error
Error?
Type: Function
context
Object? The context object
Returns boolean