Bun
Tags: webdev, bunjs, typescript
Published: 2024-02-11 04:35:56

## Wait, what is Bun

Bun is a java script runtime that is designed to be fast and efficient. It is built on top of the **JavaScriptCore engine** and uses a number of optimizations, advantages of using the low-level language Zig to make it faster.

## Install Bun and init
```bash
curl -fsSL https://bun.sh/install | bash
bun init
```

## Experiment with Elysia (Bun Framework)

Elysia is ergonomic Framework for Humans, TypeScript with End-to-End Type Safety, unified type system and outstanding developer experience. Supercharged by Bun.

Preparation:
1. Install packages
2. Configure knex
3. Configure database
4. Configure environment
5. Create migration file and run it
6. Create controller
7. Run server
8. Using docker

#### # 1. Install packages
```bash
bun add elysia knex dotenv pg
knex init
```

#### # 2. Configure knex
```js
// -- knexfile.js
require("dotenv").config();

export const development = {
  client: "pg",
  connection: process.env.DATABASE_URL,
  migrations: {
    directory: "./db/migrations",
  }
};
```

#### # 3. Configure database
```js
// -- db.js 
const knex = require("knex");
const knexFile = require("./knexfile.js");

const environment = process.env.NODE_ENV || "development";

export default knex(knexFile[environment]);
```

#### # 4. Configure environment
```bash
// -- .env
DATABASE_URL = <YOUR_DATABASE_URI>
```

#### # 5. Create migration file and run it
run `knex migrate:make blog`

```js
/**
 * @param { import("knex").Knex } knex
 * @returns { Promise<void> }
 */
export function up (knex) {
  return knex.schema.createTable("blog", (table) => {
    table.increments("id").primary();
    table.string("title").notNullable();
    table.string("content").notNullable();
    table.string("author").notNullable();
    table.timestamp("created_at").defaultTo(knex.fn.now());
  });
}

/**
 * @param { import("knex").Knex } knex
 * @returns { Promise<void> }
 */
export function down (knex) {
  return knex.schema.dropTable("blog");
}
```

After creating migration table, run `knex migrate:latest`

#### # 6. Create controller
```js
// -- index.ts
const { Elysia } = require("elysia");
let db = require("./db");
db = db.default;
const app = new Elysia();

// -- New post
app.post("/posts/create-new-post", async (context) => {
  try {
    //Extract the title, content and author from the request body
    const { title, content, author } = context.body;

    //Insert the post into the database
    const post = await db("blog").insert({
      title,
      content,
      author,
    });

    //Send response to the client
    return new Response(JSON.stringify(post));
  } catch (error: any) {
    //Send error to the client
    return new Response(error.message, { status: 500 });
  }
});

// -- Get all posts
app.get("/posts", async (context) => {
  try {
    //Get all posts from the database
    const posts = await db.select("*").from("blog");

    //Send response to the client
    return new Response(JSON.stringify(posts));
  } catch (error: any) {
    //Send error to the client
    return new Response(error.message, { status: 500 });
  }
});

// -- Get post by ids
app.get("/posts/:id", async (context) => {
  //Extract the id from the request params
  const { id } = context.params;

  //Get the post from the database
  const post = await db("blog").where({ id });

  //If the post is not found, send a 404 response
  if (post.length === 0) {
    return new Response("Post not found", { status: 404 });
  }

  //Send response to the client
  return new Response(JSON.stringify(post));
});

// -- Update post
app.patch("/posts/:id/update-post", async (context) => {
  //Extract the id from the request params
  const { id } = context.params;

  //Extract the title and content from the request body
  const { title, content } = context.body;

  //Update the post in the database
  const post = await db("blog").where({ id }).update(
    {
      title,
      content,
    },
    ["id", "title", "content"]
  );

  //Send response to the client
  return new Response(JSON.stringify(post));
});

// -- Delete post
app.delete("/posts/:id/delete-post", async (context) => {
  //Extract the id from the request params
  const { id } = context.params;

  //Delete the post from the database
  const post = await db("blog").where({ id }).del();

  //Send response to the client
  return new Response(JSON.stringify(post));
});

app.listen(3000, () => {
  console.log("Server running on port 3000");
});
```

#### # 7. Run server

Then run `bun --watch index.ts`


#### # 8. Using Docker

run `touch Dockerfile`

```yaml
FROM oven/bun

WORKDIR /app

COPY package.json .
COPY bun.lockb .

RUN bun install

COPY . .

EXPOSE 3000

CMD ["bun", "index.ts"]
```