a first look at oak
oakdenohttprouterOak is a middleware framework for Deno’s native HTTP server and Deno Deploy. It is influenced by Koa (hence the anagram) and includes a middleware router inspired by @koa/router.
All the code for this article can be found on my GitHub.
Setup #
Deno ships as a single executable with no dependencies. However, we will also need to install deployctl
for Deno Deploy.
Install Deno Executable #
There are various ways of installing Deno depending on your operating system. If you are using Mac or Linux, the official Shell install script is recommend.
curl -fsSL https://deno.land/x/install/install.sh | sh
You can find a list of different installation methods on the official deno.land documentation and the deno_install
repo.
Install deployctl
#
With deployctl
you can run your Deno Deploy scripts on your local machine. Your scripts are run in the Deno CLI, with the correct TypeScript types for Deno Deploy. After installing Deno, deployctl
can be installed using the following command.
deno install \
--allow-read \
--allow-write \
--allow-env \
--allow-net \
--allow-run \
--no-check \
--force \
https://deno.land/x/deploy/deployctl.ts
You may need to set the PATH
variable as seen below but with your own path to the deno
excecutable in place of /Users/ajcwebdev
.
export PATH="/Users/ajcwebdev/.deno/bin:$PATH"
Create Project Files #
All we need is a directory containing an index.js
file.
mkdir ajcwebdev-oak
cd ajcwebdev-oak
touch index.js
echo '.DS_Store' > .gitignore
Create Deno Server #
Before diving into Oak, it's useful to see the underlying server code they are building upon. The Deno Standard Library has an http module with a basic hello world application. Save the following code in index.js
:
// index.js
import { listenAndServe } from "https://deno.land/std@0.111.0/http/server.ts"
listenAndServe(
":8080",
() => new Response("Hello from Deno on Localhost 8080")
)
console.log("Server running on localhost:8080")
Run Deno server #
deno run \
--allow-net index.js \
--watch \
--no-check
Server running on localhost:8080
Open localhost:8080.
Create Oak Server #
Oak is a third party module for Deno hosted on their deno.land/x service. To import one of these modules, use the following format for code URLs:
https://deno.land/x/IDENTIFIER@VERSION/FILE_PATH
If you leave out the version it will default to the most recent version released for the module. The Deno docs recommend pinning to a specific version to avoid unexpected breaking changes. At the time of this writing, the current version of Oak is https://deno.land/x/oak@v9.0.1/mod.ts
.
Application Class #
The Application
class coordinates managing the HTTP server, running
middleware, and handling errors that occur when processing requests. Two methods are generally used:
- Middleware is added via the
.use()
method. - The
.listen()
method starts the server and then processes requests with the registered middleware.
Once the server is open, before it starts processing requests, the application will fire a "listen"
event, which can be listened for via the .addEventListener()
method.
// index.js
import { Application } from "https://deno.land/x/oak@v9.0.1/mod.ts"
const app = new Application()
app.use((ctx) => {
ctx.response.body = "Hello from Oak on Localhost 8080"
})
app.addEventListener('listen', () => {
console.log(`Server running on localhost:8080`)
})
app.listen({ port: 8080 })
The middleware is processed as a stack, where each middleware function can control the flow of the response. When the middleware is called, it is passed a context (ctx
) and reference to the "next" method in the stack.
.response
accesses theResponse
object to form the response sent back to the requestor.- The
.body
method returns a representation of the request body.
Return to localhost:8080.
Respond with HTML #
To respond with HTML instead of plain text, use .headers.set
on ctx.response
and set the Content-Type
to text/html
.
// index.js
import { Application } from "https://deno.land/x/oak@v9.0.1/mod.ts"
const app = new Application()
app.use((ctx) => {
ctx.response.body = "<h2>Hello from Oak on Localhost 8080</h2>"
ctx.response.headers.set("Content-Type", "text/html")
})
app.addEventListener('listen', () => {
console.log(`Server running on localhost:8080`)
})
app.listen({ port: 8080 })
Return to localhost:8080 to see the change.
Router #
The Router
class produces middleware which can be used with an Application
to enable routing based on the pathname of the request.
// index.js
import { Application, Router } from "https://deno.land/x/oak@v9.0.1/mod.ts"
const router = new Router()
const app = new Application()
router.get("/", (ctx) => {
ctx.response.body = "<h2>Hello from Router on Localhost 8080</h2>"
ctx.response.headers.set("Content-Type", "text/html")
})
router.get("/about", (ctx) => {
ctx.response.body = "<h2>This page tells you about stuff</h2>"
ctx.response.headers.set("Content-Type", "text/html")
})
app.use(router.routes())
app.use(router.allowedMethods())
app.addEventListener('listen', () => {
console.log(`Server running on localhost:8080`)
})
app.listen({ port: 8080 })
Return to localhost:8080 to see the change.
Open localhost:8080/about to see the new about page.
Deno Deploy #
Deno Deploy is a distributed system that runs JavaScript, TypeScript, and WebAssembly at the edge, worldwide. It is a multi-tenant JavaScript engine running in 25 data centers across the world.
Run server with deployctl run
#
You can run your script like it would run on Deno Deploy with deployctl
. Include --no-check
so TypeScript doesn't explode in a giant fireball of errors. You can also add the --watch
flag to automatically restart the script when any modules in the module graph change.
deployctl run \
index.js \
--no-check \
--watch
If you return to localhost:8080 there will be no change in the application.
Initialize GitHub Repository #
git init
git add .
git commit -m "finally, another project named after a tree"
gh repo create ajcwebdev-oak
git push -u origin main
Install the Deno Deploy GitHub App #
We will be deploying this script from a URL on GitHub. Install the Deno Deploy GitHub App.
Deploy Deno script #
Sign up for a Deno Deploy account and connect the account to your GitHub. You will be taken to a page for your projects.
Create Deno Deploy Project #
Click "New Project" and enter a name for your project.
After creating your project you are given the option of using existing templates.
Connect GitHub repository #
Since we will not be using a template, scroll down to connect the GitHub repository we just created.
Paste the raw GitHub url for your function.
Click "Link" and go to ajcwebdev-oak.deno.dev.
You can use the project overview page to review your project's settings, add/remove domains, or view the deployment logs.