As I've shared yesterday about my list of microservices, today I try to implement an API Gateway with Deno. Because I've created Node.js version early, I though that it should be very simple to migrate to Deno, but not really. It taken about 3 hours of reading the documentation and some tutorials!
Here are some notes for reference later.
1. Server and HTTPOptions
Similar to Node.js, Deno provides http, a standard library to handle web server. I've played with it a little bit. Then I quickly found that there is a drop-in replacement for Express named opine.
So I switch to this lib. It works almost the same as Express, but incomplete, and the listen
method is quite different.
With Express, to set host
and port
, we can just write:
app.listen(port, host, onServerReady);
But with Opine's app
instance, the following ways didn't work:
app.listen(port, host, onServerReady);
app.listen(host, port, onServerReady);
app.listen({port, host}, onServerReady);
There is no docs/examples relating to this issue, so I have to look in the source code and see that they use HTTPOptions
and HTTPSOptions
from the standard http/server library. They didn't use the property name host
as [server.listen() in Node.js] (nodejs.org/api/net.html#net_server_listen_o..), but hostname
. So, the correct way is:
app.listen({hostname: host, port}, onServerReady);
2. HTTP Proxy
As other API Gateway, I need to map some endpoints to the actual services behind the scene. In Node.js, I use http-proxy-middleware. In Deno, there is opine-http-proxy.
I haven't dig into these libs enough yet. But the basic method I'm using shows a little bit of a difference.
With express/http-proxy-middleware, if we write something like:
app.use('/login', createProxyMiddleware('https://abc.com'));
Then, any request to {API_GATEWAY_DOMAIN}/login
will be forwarded to https://abc.com/login
.
But, with opine/opine-http-proxy, we have to write exactly the path:
app.use('/login', createProxyMiddleware('https://abc.com/login'));
3. The flags
With Node.js, we simple run node script.js
and everything should work well. But with Deno, deno run script.ts
may not work as expected. Because, Deno does not grant any permission to running script by default. So, if the script needs to access to the network, it must be started with the flag --allow-net
:
deno run --allow-net script.ts
If it also needs to load a file from hard disk, it must be started with the flag --allow-read
:
deno run --allow-net --allow-read script.ts
There is also --allow-write
to write files, --allow-env
to get environment variables, --allow-run
to run sub processes, and more here.
However we can use --allow-all
to enable all the permission so it would work as same as Node.js, but we shouldn't - that is the unique value by Deno.
4. readJson
and --unstable
flag
Because in my service there is always a service.json
file to define service settings, I need to parse JSON file.
Similar to Node.js, Deno provides a standard library called fs too. And I found that there is few familiar methods to deal with JSON content there.
However, the following does not work:
import { readJson } from "https://deno.land/std/fs/mod.ts";
As you see, it loads many unnecessary modules and requires to add --unstable
to the command, for example:
deno run --allow-net --allow-read --unstable app.ts
In the case you don't like the unstable things, you can refer their read_json.ts and write your own method, for example:
const readJson = async (filePath: string) => {
const content = await Deno.readTextFile(filePath);
return JSON.parse(content);
};
5. Built-in logger
The log library in Deno looks quite similar to Python logging module. Because I also work with Python so this is not very hard to get familiar with.
This lib supports file rotating, custom format and handlers. So we don't need to use any third party module as with Node.js we must.
6. Which docker image for Deno should be chosen?
While Deno team didn't build any official docker image yet, I recommend to use hayd/deno-docker. Because it is updated regularly and there is a discussion about making it official.
Conclusion
Node.js is cool. Deno is cool too. There is no package.json
, nor node_modules
. That makes things look more simple and clean. The standard libraries and built-in tools are great. But this ecosystem will need more time to mature...