Oak, the successor of Koa (which is the spiritual successor of Express in Node.js), is the most popular choice when it comes to building web applications with Deno. However, when saying web applications with Deno, itâs often not for anything visible in the browser (excluding server-side rendering of a frontend application). Instead, Oak, a web application framework for Deno, enables you to build server applications in Deno. As a backend application, it is the glue between your frontend application and a potential database or other data sources (e.g. REST APIs, GraphQL APIs). Just to give you an idea, the following is a list of tech stacks to build client-server architectures:
Oak is exchangeable with other web application frameworks for the backend the same way as React.js is exchangeable with Vue.js and Angular.js when it comes to frontend applications. The Deno ecosystem doesnât offer only one solution, but various solutions that come with their strengths and weaknesses. However, for this application we will use a Oak server, because it is the most popular choice when it comes to building JavaScript backend applications with Deno.
Letâs start by using Oak in your Deno application. In your src/server.ts TypeScript file, use the following code to import Oak, to create an instance of an Oak application, and to start it as Oak server:
Remember to put the event listener (addEventListener) in front of the actual listening (listen), otherwise the listener will never get executed. Everything that should happen after your Oak application has started goes into the addEventListener methodsâs callback function . The listen method takes as first parameter a configuration object with the port â which we initialized with a property shorthand in an object â for the running application. Thatâs why after finally starting it, the should be available via http://localhost:8000 in the browser.
The Oak application has two methods: use and listen. While the listen method starts the server and starts processing requests with registered middleware, the use method sets up the middleware in the first place. We will set up one basic middleware with Oak before diving into this topic more in depth later:
This new middleware as a function will process all incoming requests for the Oak server. Try it yourself by running deno run --allow-net server.ts on the command line and visiting your browser on http://localhost:8000 . You should see the âHello Denoâ text showing up.
Context in Oak represents the current request which goes through Oakâs middleware. In code you see it often as context or ctx . In the previous code, we have used Oakâs context to return a text to our browser by using the contextâs response objectâs body:
This is one of the most straightforward usages of context in a Oak middleware. The context holds several useful properties. For example, you have access to the currently incoming request from the client with ctx.request while you also decide what to return to the client with ctx.response . You will see in the next sections how to use context for different use cases.
Essentially every Oak application is a just a series of middleware function calls. If there are more than one middleware, we need to understand how they are called and how to determine the order of the call stack. Letâs start with one middleware which prints the HTTP method and the URL of the incoming request on the command line when visiting the application in the browser:
The command line should output HTTP GET on http://localhost:8000/ . Every time a user visits a URL in a browser, a HTTP GET method is performed to the web server. In our case, the HTTP request returns just a text to the browser which reads âHello Denoâ. Now, what happens if we have two middleware instead of one:
The command line should log âHTTP GET on http://localhost:8000/ â, but not âreturning a response â¦â as text. Oak stops after the first middleware in the series of middleware has been called. In order to jump from one middleware to the next middleware, we have to use Oakâs next function with async/await:
Now the output on the command line should read the following:
Finally both middleware are called after each other. You can manipulate the order of when each middleware should be called by moving the next functionâs invocation around:
The output on the command line should read:
Basically ânextâ is the next middleware in the series of middleware you are calling. If ânextâ happens before the actual implementation logic of the middleware where itâs used (like in the last example), the next middleware is executed before the implementation logic of the current middleware.
A middleware function, because itâs a function, can be extracted as such and reused as middleware in your Deno application:
Often abstract middleware is often available as library for Oak. By using Oakâs use method, we can opt-in any third-party middleware. Eventually you will run in a few of these middleware when using Deno for larger projects.
Routes in web applications for the backend are used to map URIs to middleware. These URIs could serve a text message, a HTML page, or data in JSON via REST or GraphQL. In a larger application, this would mean having several routes (middleware) which map to several URIs.
In Oak, the router middleware is everything needed for a route, because routes are just another abstraction on top of middleware. Letâs set up such a single route with Oakâs Router:
The route points to the root ( / ) of your domain. In the browser, you can visit this route with http://localhost:8000/ or http://localhost:8000 without the trailing slash. After starting the Deno application, visit the browser to see what it outputs for you. You should see the printed âHello Denoâ there.
There are a few more gotchas for the router middleware. For example, it can be used for more than one URI:
When you visit the running application in the browser, you can navigate to all these paths to receive different texts. Itâs also possible to have more than one Oak Router to group your applicationâs routes into domains:
Essentially every Oak application is a just a series of routing and middleware function calls. You have seen the former, the routing with one or multiple routes, and the latter for enabling these routes or other utilities (e.g. logging). Both, middleware and routes, have access to Oakâs context object for the processed request.