In this tutorial, we show you how to go about building microservices with Deno, and introduce you to Reno — a thin routing library for Deno. We’ll explore how we can use this newer JavaScript platform to build a microservice that exposes endpoints for acting on a database.
Deno is a JavaScript and TypeScript runtime from Node.js creator Ryan Dahl that aims to address some of the latter technology’s shortcomings, such as simplifying the module path lookup algorithm and more closely aligning the core APIs with their browser-based equivalents. Despite these fundamental differences, the potential applications of Deno and Node.js are mostly identical. One of Node’s core strengths lies in building HTTP services, and the same can be argued for Deno.
Writing HTTP Servers with std/http
Before we introduce a routing library or contemplate our data access layer, it would be useful to step back and build a simple HTTP server with the std/http
module, which is part of Deno’s standard library. If you haven’t already, install Deno. In a Unix-type operating system, you can run:
$ curl -fsSL https://deno.land/x/install/install.sh | sh -s v1.3.0
Note that this tutorial has been developed against 1.3.0 (and std 0.65.0 as we’ll see later), but any later 1.x versions you may be using should be compatible. Alternatively, if you’re running an older version of Deno, you can upgrade to 1.3.0 with the deno upgrade
command:
deno upgrade --version 1.3.0
You can verify that the expected Deno version has been installed with deno --version
.
We’re now in a position to build an HTTP server. Create a directory, within your usual development directory, named deno-hello-http
, and open it in your editor. Then, create a file called server.ts
, and use the listenAndServe
function within std/http
to build our server:
import { listenAndServe } from "https://deno.land/std@0.65.0/http/mod.ts";
const BINDING = ":8000";
console.log(`Listening on ${BINDING}...`);
await listenAndServe(BINDING, (req) => {
req.respond({ body: "Hello world!" });
});
Developer Experience Protips
If you’re using VS Code, I’d heavily recommend the official Deno extension, which provides support for Deno’s path resolution algorithm. Additionally, you can run deno cache server.ts
to install the dependencies and their TypeScript definitions, the latter serving as an invaluable API guide when writing your code.
We can start our server by running deno run --allow-net server.ts
in our shell. Note the --allow-net
permissions flag, granting our program with network access. Once listening on port 8000
, we can target it with a HTTP request:
$ curl -v http://localhost:8000/ ; echo
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< content-length: 12
<
Hello world!
Great! With a few lines of TypeScript, we’ve been able to implement a simple server. That said, it isn’t particularly well-featured at this point. Given that we consistently serve "Hello world!"
from our callback function, the same response will be returned for any endpoint or HTTP method. If we hit a server with POST /add
, we’ll receive the same headers and body:
$ curl -v -d '{}' http://localhost:8000/add ; echo
> POST /add HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Length: 2
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 200 OK
< content-length: 12
<
Hello world!
We can limit the existing response to GET /
by conditionally checking the url
and method
properties of our callback’s req
parameter:
import {
listenAndServe,
ServerRequest,
} from "https://deno.land/std@0.65.0/http/mod.ts";
const BINDING = ":8000";
console.log(`Listening on ${BINDING}...`);
function notFound({ method, url }: ServerRequest) {
return {
status: 404,
body: `No route found for ${method} ${url}`,
};
}
await listenAndServe(BINDING, (req) => {
const res = req.method === "GET" && req.url === "/"
? { body: "Hello world" }
: notFound(req);
req.respond(res);
});
If we restart our server, we should observe that GET /
works as expected, but any other URL or method will result in a HTTP 404:
$ curl -v -d '{}' http://localhost:8000/add ; echo
> POST /add HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Length: 2
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 404 Not Found
< content-length: 28
<
No route found for POST /add
std/http
Beyond Simple Services
Bootstrapping trivial HTTP servers with Deno and std/http
has proven to be relatively straightforward. How does this approach scale for more complex services?
Let’s consider a /messages
endpoint that accepts and returns user-submitted messages. Following a RESTful approach, we can define the behavior of this endpoint and of our service overall:
Continue reading Building Microservices with Deno, Reno, and PostgreSQL on SitePoint.
No comments:
Post a Comment