Build an HTTP server in Bun
Tags: javascript, typescript, programming, tutorial
Published: 2023-09-19 19:53:47

As of last week, Bun has taken over the JavaScript world. In this post, we will see how to create an HTTP server in Bun using the Elysia Framework. Here is the [link](https://github.com/Sadeedpv/Bun-web-server) to the full source code of this project.

## So, What is Bun?

> Bun is a new JavaScript Runtime built from scratch to serve the JavaScript ecosystem.


![Bun Meme](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4wk68q6462uct4gbbmpw.jpg)

Bun has built-in TypeScript support and is blazingly fast ⚡earning it the favor of many JavaScript & TypeScript Developers 💘. 

![Bun Meme](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rajtbiqs0e893k2ygp7g.jpg)

## Installing Bun

Installing Bun is very simple. All you have to do is:
```
curl -fsSL https://bun.sh/install | bash
```

If you like to know more about the installation process, here is the [link](https://bun.sh/docs/installation)

> Note that Bun is not yet compatible with Windows, But you can still install if you have [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) installed on your system.

## Creating an HTTP server using Elysia Framework

[Elysia](https://bun.sh/guides/ecosystem/elysia) is a Bun-first performance focused web framework that takes full advantage of Bun's HTTP, file system, and hot reloading APIs.

Let's first initialize our Elysia app:
```
bun create elysia myapp
cd myapp
bun run dev
```

## Let us Build our server

In this tutorial, I will be building a simple TODO Application. For building the application, I will be using the SQLite Database. The cool thing about Bun is that it has completely free SQLite Database built in the runtime. If you like to read more about the `bun:sqlite`, here is the [docs](https://bun.sh/docs/api/sqlite)

In our `src/index.ts`, we will declare our Elysia app:
```ts
import { Elysia } from 'elysia'

const app = new Elysia();
app.get('/', () => "Hello World!");
app.listen(8000);
console.log(
  `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`
);

```

If you want to use environment variables:
```ts
app.listen(Number(Bun.env.PORT));

console.log(
  `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`
);

```

You can define your Routes with many built-in methods like:

```
app.get('/', () => {});
app.post('/', () => {});
app.put('/', () => {});
app.patch('/', () => {});
app.delete('/', () => {});
``` 

Retrieving the path parameter is also very easy just like any other Backend Framework like Express.js:

```ts
// Both does the same thing

app.get("/hello/:name", ({ params: { name } }) => {
  return `Hello ${name}!`;
});

app.get("bye/:name", (context) => {
  return `Hello ${context.params.name}`;
});

```

If you have many paths with the same prefix, you can Group them. Grouping allows you to combine multiple prefixes into one. Since we do not require that many routes to build this application, we do not need to Group the paths.

```ts
app.group('/user', app => app
    .post('/sign-in', signIn)
    .post('/sign-up', signUp)
    .post('/profile', getProfile)
)
```
You can also install the `cors` plugin which adds support for customizing Cross-Origin Resource Sharing behavior.

Install it with:
```
bun add @elysiajs/cors
```
Then use it:
```
import { cors } from "@elysiajs/cors";

const app = new Elysia();
app.use(cors());
```
In order for us to build this application, first we need to initialize our Database. Let's take a look at how we can do that:

```ts
import { Database } from "bun:sqlite";

// Create DB If not Exists
const DB = new Database("mydb.sqlite", { create: true });
```

Now, we need to create the Table

```ts
DB.query(
  `CREATE TABLE IF NOT EXISTS MESSAGES(
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  message TEXT
);`
).run();
```
After creating the relation, now we need to implement the `GET` and `POST` request. Our `GET` request would look something like this

```ts
app.get("/", (context) => {
  const query = DB.query(`SELECT * FROM MESSAGES;`);
  const result = query.all();
  console.log(result);
  context.set.status = 200;

  return new Response(JSON.stringify({ messages: result }), {
    headers: { "Content-Type": "application/json" },
  });
});
```
We used the `db.query()` method on your Database instance to prepare a SQL query and used `.all()` to run a query and get back the results as an array of objects.

Our `POST` request would look something like this:

```ts
app.post(
  "/add",
  ({ body }:any) => {
    const message = body?.message;
    console.log(message);
    const query = DB.query(`INSERT INTO MESSAGES (message) VALUES (?1)`);
    query.run(message);
    return new Response(JSON.stringify({ message: "Added" }), {
      headers: { "Content-Type": "application/json" },
    });
  });
```
As you can see here, I am using the `any` type. Instead of using the `any` type, what we can do is
```ts
import { Elysia, t } from "elysia";

app.post(
  "/add",
  ({ body }) => {
    const message = body?.message;
    console.log(message);
    const query = DB.query(`INSERT INTO MESSAGES (message) VALUES (?1)`);
    query.run(message);
    return new Response(JSON.stringify({ message: "Added" }), {
      headers: { "Content-Type": "application/json" },
    });
  },
  {
    body: t.Object({
      message: t.String(),
    }),
  }
);
```
> Note that we used context.set.status to set the StatusCode of the response


Lets try running our application:
```console
curl -X POST http://localhost:8000/add -H "Content-Type: application/json" -d '{"message":"This is a Reminder!"}'  
curl http://localhost:8000/
```
And Booom!! 💥💥
```console
{"message":"Added"}
{"messages": [{"id":1, "message": "This is a Reminder!"}]}
```

### Here are some tasks for you:
- Create `PUT` and `DELETE` requests to update or DELETE the Database
- Implement error handling 

### CONCLUSION

I hope you gained some new insights from this post. As you can see from the graph, Bun is much faster than Node as of now.
![Bun Speed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/np2zs3hrbk5lv1ooaoxp.png)
Also, take a look at how fast Elysia is compared to Express:

![Express Speed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u65r8pmrjsn23k6elpqm.png)

### References

If you like to read more about `bun:sqlite`, [read more](https://bun.sh/docs/api/sqlite)
If you like to read more about `Elysia`, [read more](https://elysiajs.com/quick-start.html)
If you want the link to the full source code in GitHub, [click here](https://github.com/Sadeedpv/Bun-web-server)