Outline
All of this project's code can be found in the First Look monorepo on my GitHub.
Introduction
Oak 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.
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
executable 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.
Add 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 Oak Server with deployctl
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.
Sign Up for Deno Deploy
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.