How to create middleware in Deno's Oak
overview
Oak is a framework with the ability to perform processing between requests and responses using middleware. Middleware provides access to request objects, response objects, and the following middleware functions: Middleware is used within Oak’s route handlers.
Here I will show you how to create middleware with Oak using the following versions:
- Oak v9.0.0
- Deno v1.15.3
In addition, all the code created this time is posted on the following GitHub repository.
https://github.com/wiblok/Oak.js
How to define middleware
In Oak.js the main way to use middleware looks like this:
- Application level middleware
Middleware that applies to the entire application. Define using
app.use()
.
import { Application } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
app. use((context, next) => {
console.log('This is an application-level middleware');
next();
});
- Router level middleware
Middleware applied to a specific route or route group. Define using
router.use()
.
import { Application, Router } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
const router = new Router();
router.use((context, next) => {
console.log('This is a router-level middleware');
next();
});
app.use(router.routes());
app.use(router.allowedMethods());
These middlewares help perform functions at specific points as individual requests pass through your application. Each middleware function either completes the request-response cycle or passes the request and response objects to the next middleware function in the stack.
How to create application level middleware
The example below creates an application-level middleware named myMiddleware
.
application.ts
import { Application } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
const myMiddleware = async (context, next) => {
// middleware processing
console.log('run middleware');
await next();
}
app. use(myMiddleware);
app. use((context) => {
context.response.body = { message: 'Hello, World!' };
});
await app.listen({ port: 8000 });
This code is for creating a web server with Deno using the Oak framework. Below is a bullet point description of the code.
import { Application } from "https://deno.land/x/oak/mod.ts";
- Import the Oak framework with the name
Application
.
- Import the Oak framework with the name
const app = new Application();
- Call
new Application()
to create a new Oak application and assign it to theapp
variable.
- Call
const myMiddleware = async (context, next) => { ... }
- Define a function named
myMiddleware
. - This function is called middleware and is used by Oak to process requests.
- Define a function named
console.log('running middleware');
- As part of the processing within the middleware function, output the message “middleware execution” to the console.
app.use(myMiddleware);
- Apply the created middleware function (
myMiddleware
) to your Oak application using theapp.use
method. - This will force all requests to go through this middleware function.
- Apply the created middleware function (
app.use((context) => { ... });
- Define a route handler for GET requests using the
app.use
method. - In the processing inside the arrow function,
- Define a route handler for GET requests using the
I am sending a JSON formatted response using the context.response.body
property.
await app.listen({ port: 8000 });
- Start the application on port 8000 using the
app.listen
method.
- Start the application on port 8000 using the
You can send a request using the command below.
curl -X GET http://localhost:8000
How to create router level middleware
The example below creates a router-level middleware named myMiddleware
.
routeMiddleware.ts
const myMiddleware = async (context, next) => {
// middleware processing
console.log('run middleware');
await next();
}
export default myMiddleware;
routeMain.ts
import { Application } from "https://deno.land/x/oak/mod.ts";
import myMiddleware from './routeMiddleware.ts';
const app = new Application();
app. use(myMiddleware);
app. use((context) => {
context.response.body = { message: 'Hello, World!' };
});
await app.listen({ port: 3000 });
console.log('Server is running on port 3000');
When I run this code, it runs the middleware for every request and prints ‘running middleware’ to the console.
curl -X GET http://localhost:3000
How to use built-in middleware
The Oak framework has built-in middlewares, which provide specific functionality. For example, you can serve static files with code like this:
builtin.ts
import { Application, send } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
// Serve static files using send middleware
app. use(async (context) => {
await send(context, context.request.url.pathname, {
root: `${Deno.cwd()}/public`,
});
});
await app.listen({ port: 3000 });
console.log('Server is running on port 3000');
This code serves static files in the public
directory. For example, if you access http://localhost:3000/sample.txt
in your browser, you will see public/sample.txt
.
curl -X GET http://localhost:3000/sample.txt
How to use 3rd party middleware
Deno can take advantage of third-party middleware available from deno.land/x. For example, you can use middleware for log output called oak_middleware_logger
with the following code.
deno install oak_middleware_logger
Now write the code to incorporate this package into your application.
thirdparty.ts
import { Application } from "https://deno.land/x/oak/mod.ts";
import logger from "https://deno.land/x/o
ak_middleware_logger/mod.ts";
const app = new Application();
// output log using logger middleware
app.use(logger.logger);
app.use(logger.responseTime);
app. use((context) => {
context.response.body = { message: 'Hello, World!' };
});
await app.listen({ port: 3000 });
console.log('Server is running on port 3000');
This code runs the oak_middleware_logger
middleware for every request, which prints the details of the HTTP request to the console.
curl -X GET http://localhost:3000
How to create error handling middleware
Error handling middleware handles errors passed to it by other middleware. Below is an example of creating an error handling middleware.
errorhandling.ts
import { Application } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
app. use(async (context, next) => {
try {
await next();
} catch (err) {
console. error(err. message);
context.response.status = 500;
context.response.body = 'Something went wrong';
}
});
app. use((context) => {
throw new Error('Something went wrong');
});
await app.listen({ port: 3000 });
console.log('Server is running on port 3000');
This code throws an error after the error handling middleware has run. This error is caught by the error handling middleware and an error message is printed to the console. Also, an error message is returned to the client with a 500 error (Internal Server Error).
curl -X GET http://localhost:3000