Hello Learners. I am sure you all are staying home and staying safe. Tough time but good opportunity to learn a lot. Be it due to different work style, life style or just getting more time due to cut down on commuting to work premises.
So, as we all heard that Deno
is coming out and is created by the same guy who created much popular Node
, Ryan Dahl. I was excited too and finally 1.0.0
came out.
And I started to have some hands on with it. Due to that very reason, I am writing this blog to document my experience.
I am not going to detail out on how to install deno
or how to use the modules in details. They are available on official documentation page.
These are good to start with:
- Manual: https://deno.land/manual
- v1.0.0: https://deno.land/v1
In this post, I'll mention what I tried, what I liked about it and what I am planning to explore further. But, as technologies keeps evolving, these lists are not like finite.
Let's get started.
What is Deno?
As per official documentation, Deno is a secure
runtime for JavaScript
and TypeScript
.
It is like node but there are lot of enhancements done with it.
To summarize few:
- It has TypeScript at its core
- Features of Modern JavaScript
- No package manager
- Has first-class
await
- Secure
I am pretty excited to get into it. Are you?
Why Deno?
It was announced almost 2 years ago and Ryan Dahl mentioned some of the regrets he had with some early decisions in Node.
Here is the video for reference.
https://www.youtube.com/watch?v=M3BM9TB-8yA
So Deno
is like second iteration of a server side apps powered by JavaScript.
Now, it is v1.0.0
and officially stable, we can safely start using it as there won't be any breaking changes till we get to v2.0.0
. :)
What I built?
Okay, so here are the points that I wanted to cover/explore:
-
Server: REST Api server built on
Deno
- Client: A client application to consume those API
- Docker: Dockerise the complete working application
Server:
I wanted to have a very basic REST API which can be used for CRUD operation. So, here is what I have decided to create for API:
Route | Method | Summary |
---|---|---|
/todos |
GET | List all todos |
/todos/:id |
GET | Get one todo by Id |
/todos |
POST | Create a todo |
/todos/:id |
PUT | Update a todo by Id |
/todos:/id |
DELETE | Delete a todo by Id |
Looks familiar from Node and express perspective, right?
The first thing, I wanted to have is something similar to express
or koa
that we use in node
.
After some look around and documentation, I found something similar to koa
for Deno and it is called oak
. Below is the link to the module.
Here is the basic server setup to get started:
index.ts
import { Application } from "./deps.ts";
import { HOST, PORT } from "./config.ts";
// Instantiate the application
const app = new Application();
const listenOptions = {
port: Number(PORT),
};
console.log(`Listening on ${HOST}:${PORT}...`);
// start the server
await app.listen(listenOptions);
deps.ts
export {
Application,
Router,
send,
Context,
} from "https://deno.land/x/oak/mod.ts";
export { v4 } from "https://deno.land/std/uuid/mod.ts";
After basic server setup, here is how I have created the routes:
routing.ts
router
.get("/todos", getTodos)
.get("/todos/:id", getTodo)
.post("/todos", addTodo)
.put("/todos/:id", updateTodo)
.delete("/todos/:id", deleteTodo);
I have imported this into index.ts
and then added the route:
import router from "./routing.ts";
...
app.use(router.routes());
...
At this point, I was able to complete and test my REST APIs and all were working fine.
Now, to serve the client page, I have added one more route into index.ts
after app.use(router.routes())
line as shown below:
app.use(async (context: Context) => {
await send(context, context.request.url.pathname, {
root: `${Deno.cwd()}/public`,
index: "index.html",
});
});
The above route/code helped me to server my react app's index.html
file from public folder
Running the Deno server
So, to run the server, we use deno run ENTRY_POINT_FILE
. As we are ready to run the application, let me explain security part a bit.
In node, we don't specify whether the application can access the environment
variables or can read/write file system or can access the network.
In Deno, these accesses are not provided by default due to sand-boxing. If required, we have to pass the arguments to our deno run
command. The application that I worked on, below is the command to make it work properly.
deno run --allow-env --allow-net --allow-read --allow-write index.ts
You can see following arguments flag:
-
--allow-env
: To read environment variables in our codebase -
--allow-net
: Helpful for networking -
--allow-read
: Allows to read filesystem -
--allow-write
: Allows to write to filesystem
More can be read on official documentation page.
Good to know
We can create a
dependency.ts
[deps.ts] to have all third-party modules at one place. This helps us to manage dependencies better. Any alternate way? Thoughts?In the
index.ts
, you can observe that the last line is usingawait
withoutasync
. This is one of the feature of Deno where it has first-classawait
.Moreover, created some other files and introduced some middleware as per the
oak
setup.I have used simple
json
file to persist the data for REST API, so no Database. ;)
Client
Nothing much here to be honest. I used create-react-app
to scaffold a basic react application but in TypeScript. Used redux for statemanagement.
Good to know:
-
My deno application server was configured on different port than the client application. So, to make the api call, proxy was required. This can be easily achieved with
create-react-app
by doing aproxy
entry into thepackage.json
.
"proxy": "http://localhost:4000"
NOTE: This is for development purpose only
Nothing fancy for client application and so I have used manual process to copy the build output into server's public folder. It wasn't the primary goal.
How client app looks?
Docker
To dockerise the app, I have created two files:
- Dockerfile
- docker-compose.yml
For, dockerfile, I have used hayd/deno:alpine-1.0.0
image. This worked out of the box. Here is the sample file
FROM hayd/deno:alpine-1.0.0
EXPOSE 4000
WORKDIR /app
USER deno
COPY deps.ts .
RUN deno cache deps.ts
COPY . .
RUN deno cache index.ts
CMD ["run", "--allow-net", "--allow-env", "--allow-read", "--allow-write", "index.ts"]
The above file's CMD
might look bit strange but as explained above, we have to pass these arguments depending on the nature of application and sandbox feature of Deno
.
And the docker-compose.yml
version: "3.7"
services:
deno:
image: "deno-todo:0.0.1"
build: .
ports:
- "4000:4000"
networks:
- deno
networks:
deno: {}
What I liked about Deno
As we have seen how things progressed while I was trying out deno, here is what I liked:
- No package manager
- Once module is cached, the application starts really quick
- Sandboxing for better security
- ES6 support out of the box
- TypeScript
Yet to explore
Okay, so as I mentioned, this is my first hands on with Deno
and there are lot to be explored but here are few things that I want to go into deeper:
- What would be the best way to manage the versioning of the third party modules.
- Server side rendering
- Hot reloading of deno server
- Creating own module for deno
- More on middlewares
- Creating own middlewares
- Authentication
- Using github action for the module and make it available on github to be used by others
- and many more....
There would be lot more to learn and explore but this is a starting point for me to take a next step. I am hoping that his will give you all some insight.
Conclusion
In short, I liked Deno so far and this is something new and refreshing which keeps human being more motivated. I will try to keep up with it and will come up with more articles as time permits.
Source code is available on github.
https://github.com/elanandkumar/deno-todo-app
For now, Stay Home, Stay Safe and Keep Learning.
Happy Learning!
Top comments (0)