# Fighting Errors: My Story of Building an API with Hono & Drizzle

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

## About Project

In this project, we will **build a bridge** that can connect an API with a database.

* **Hono** will be the **architect** who designs and builds the main bridge.
    
* **Drizzle** serves as the **inspector** who maintains type safety, This will help us prevent data and query errors, and ensure that every "vehicle" (data) that passes has the proper credentials.
    

The goal is simple: to create seamless and secure communication between the API and the database, and avoid various common issues.

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

## **And This My Story**

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

## Gearing Up (Preparation)

Before we start writing code, let's get all the tools and "ammunition" ready.

1. **Main Tools**
    
    * **Visual Studio Code (VS Code):** Get it here: [https://code.visualstudio.com/](https://code.visualstudio.com/).
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758852177500/bbd43d59-b48e-4a62-9292-e92573590b9a.png align="center")
        
        Click download for windows if you use windows, else you can click other platform in below download for windows
        
    * **Node.js:** Make sure you have this installed. If not, you can follow the guide in your own article: [http://blog.alchemists.my.id/](http://blog.alchemists.my.id/)[d](https://the-digital-alchemists-log.hashnode.dev/download-node-js-and-try-with-git-bash)[ownload-node-js-and-try-with-](http://blog.alchemists.my.id/fighting-errors-my-story-of-building-an-api-with-hono-and-drizzle)[git-bash](https://the-digital-alchemists-log.hashnode.dev/download-node-js-and-try-with-git-bash) or [https://the-digital-alchemists-log.hashnode.dev/download-node-js-and-try-with-git-bash](https://the-digital-alchemists-log.hashnode.dev/download-node-js-and-try-with-git-bash)
        
2. Setting Up the Worksplace
    
    * **Create Your Project Folder:** Make a new folder for this project using *Git Bash* or your *File Explorer*, for example i create folder with git bash
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758852428916/f9851b01-a82d-4445-9eb7-eb3433a19715.png align="center")
        
    * **Create Basic Structure:** inside your project folder, make the following folder and files:
        
        * Create a new folder named `db`
            
        * inside the `db` folder, create three files: `schema.js` , `index.js` , and `seed.js`
            
3. Installing the “Troops” ( Dependencies )
    
    Open terminal in Visual Studio Code with click CTRL + \` (Grave accent above the tab key on the keyboard)
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758853877456/0639a846-72b8-4e54-9d46-4bec8c5b6d5f.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758853986652/0cee5fad-0811-4b32-a8ba-c1e09adc59c6.png align="center")
    
    Choose git bash
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758853991712/dbd6dd7b-dc00-45f3-991c-fe61c9468a9c.png align="center")
    
    And run these commands one by one:
    
    1. initialize the NPM project:
        
        ```bash
        npm init -y
        ```
        
        after initialize npm go to file package.json and add `“type“: “module“,`
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758896669684/7f14057d-2e31-452d-adf4-0d88aa0c3aec.png align="center")
        
    2. Install Core Dependencies: (Drizzle ORM, PostgreSQL Driver, Dotenv)
        
        ```bash
        npm install drizzle-orm pg dotenv
        ```
        
    3. Setup `.env` , create file `.env` and write like this
        
        This Query
        
        ```javascript
        DATABASE_URL="postgresql://[user]:[password]@[host]:5432/[name-database]"
        ```
        
        This my code
        
        ```javascript
        DATABASE_URL="postgresql://postgres:postgres@localhost:5432/dbproject2"
        ```
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758954029903/adea52c3-278d-44e6-98a4-0600140d4089.png align="center")
        
    4. install the Server Framework: (Hono)
        
        ```bash
        npm install hono @hono/node-server
        ```
        
    5. install Development Dependencies: (Drizzle Kit for migration and Nodemon for auto-restart)
        
        ```bash
        npm install -D drizzle-kit nodemon
        ```
        
    6. Add Migration Script, in package.json file like this
        
        ```javascript
          "scripts": {
            "db:generate": "drizzle-kit generate",
            "db:migrate": "drizzle-kit migrate",
            "dev": "node --watch server.js",
            "start": "node server.js"
          },
        ```
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758898054060/6fede809-821b-4243-a5d7-3fe1d34fb0a0.png align="center")
        
    7. Configuration Drizzle kit, create file `drizzle.config.js` and write like this
        
        ```javascript
        import 'dotenv/config';
         
        export default {
          dialect: 'postgresql',
          schema: './db/schema.js',
          out: './drizzle',
          dbCredentials: {
            url: process.env.DATABASE_URL,
          },
        };
        ```
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758953772489/0573878c-e7bd-4ef6-8ac9-c82a602c8317.png align="center")
        
4. **Extension and Git ( optional )**
    
    1. API Tester Extension: install the Echo API extension in Visual Studio Code to test out API later. (Search for `Echo API` in the Extension Marketplace ).
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758855159881/a4fedac6-9559-4529-9baf-0e5a46d0c432.png align="center")
        
    2. initialize Git
        
        ```bash
        git init
        ```
        

Congratulations, you have finished preparing the equipment.

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

## Code Code !!

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

## **Main Content**

we will enter the core of the project

## **Create Code**

1. `db/schema.js` (The Blueprint Book) 📘
    
    * This file is the **blueprint** for your database table. Here, you tell Drizzle exactly what kind of columns the `student` table needs.
        
    * **Import Tools**: Import `pgTable` , `serial` , `varchar` , `timestamp` from `drizzle-orm/pg-core`
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758953113354/42020e21-c9bc-445b-a44e-15066e1c8f16.png align="center")
        
    * **Create The Table:** create table student like table student in database
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1759113221086/449dd0a5-0303-412c-8b66-93ee7a370822.png align="center")
        
    * run generation and migrate
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758955806511/5b00c6eb-57e8-4f6a-82d5-9d168cb90d77.png align="center")
        
2. `db/index.js` (The Bridge Guide) 🌉
    
    * This file is the **actual connection point**. It takes the database URL from your `.env` file and creates a **connection pool** (like a waiting area for connections) so your Hono server can talk to the database anytime it needs to.
        
    * **Import Essentials:** Import `drizzle`, the `Pool` from `pg` , `dotenv` , and your new `schema`
        
    * **Create Connection Pool:** Set up the `Pool` using the `DATABASE_URL` from the environment.
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758955896888/73d01e24-d2d7-4cf0-b316-e96d053593ce.png align="center")
        
    * **Initialize Drizzle:** Use the pool to create the `db` object—this is the **magic key** you’ll use in all your API routers.
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758956039374/7554aaa6-22e3-41f2-abbc-862f05123ba3.png align="center")
        
3. `db/seed.js` (The Initial Filler) 🌱
    
    * This is your **first round of data**. Before you build the API endpoints, it's good practice to insert some initial data so you can test the "Read" functions right away.
        
    * **Import Essentials:** `db` from `./index.js` and student table from `./schema.js`
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758956346845/a4e20b50-460e-4cae-bbe4-eb16b27e4a40.png align="center")
        
    * **The Main Function & Insert Data:**
        
        ```javascript
        import { db } from "./index.js";
        import { student } from "./schema.js";
        
        async function main() {
          await db.insert(student).values([
            {
              id: 1,
              name: "Jeromy Alexanderia",
              address: "12 Abdelsalam Aref Street, Alexandria, Egypt",
            },
            {
              id: 2,
              name: "Jhon Doe",
              address: "145 Willow Lane, Springfield, IL, USA",
            },
            {
              id: 3,
              name: "Xia gang",
              address: "9 Fuxing Road, Chaoyang District, Beijing, China",
            },
          ]);
          console.log(" Student data successfully seeded.");
        }
        
        main();
        ```
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758956579545/35f907c3-899b-43ca-ad60-71caae2c6da2.png align="center")
        

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

## Building the Control Tower 🏗️

This is the most exciting part! In the `server.js` file, we're going to power up the **Hono** engine and connect it to **Drizzle** (our `db` Magic Key).

We will create **five API routes** to handle the full CRUD lifecycle (*Create, Read, Update, Delete*), allowing our database to finally 'speak' to the outside world.

### Step-By-Step

1. **Importing Essentials (Powering Up):**
    
    * `Hono` as the core server engine, `db` object, `student` table from drizzle and `eq` function
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758982388035/9db3986d-1479-4158-a37e-d38671ec03b4.png align="center")
        
2. **Route \[C\] Create:**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758982448390/55557279-61c4-4bc5-b89d-775227dac0cc.png align="center")
    
3. **Route \[R\] Read All:**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758982486722/8c67042b-9c0f-4a6b-8498-0a25318b0c2e.png align="center")
    
4. **Route \[R\] Read One:**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758982523657/912acc05-5331-484d-b17a-09bf7acf988d.png align="center")
    
5. **Route \[U\] Update:**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758982553159/c49bd8c0-6e6d-458e-a853-9fc3b8dcd1a3.png align="center")
    
6. **Route \[D\] Delete:**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758982582088/96b89ce2-a9c5-4f7c-a157-8ff1f81dc7e1.png align="center")
    
7. **Info about API and server initialize:**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758982681122/0596f184-4361-4810-8350-0dbda62480cc.png align="center")
    
8. **ALL Code:**
    
    ```javascript
    import { Hono } from 'hono';
    import { serve } from '@hono/node-server';
    import { db } from './db/index.js';
    import { student } from './db/schema.js';
    import { eq } from 'drizzle-orm';
     
    const app = new Hono();
     
    // [C] Create
    app.post('/api/student', async (c) => {
      const data = await c.req.json();
      const result = await db.insert(student).values(data).returning();
      return c.json({ error: false, data: result[0] }, 201);
    });
     
    // [R] Read All
    app.get('/api/student', async (c) => {
      const result = await db.query.student.findMany();
      return c.json({ error: false, data: result });
    });
     
    // [R] Read One
    app.get('/api/student/:id', async (c) => {
      const id = Number(c.req.param('id'));
      const result = await db.query.student.findFirst({
        where: eq(student.id, id),
      });
      if (!result) return c.json({ error: true, message: 'Not found' }, 404);
      return c.json({ error: false, data: result });
    });
     
    // [U] Update
    app.put('/api/student/:id', async (c) => {
      const id = Number(c.req.param('id'));
      const data = await c.req.json();
      const result = await db
        .update(student)
        .set(data)
        .where(eq(student.id, id))
        .returning();
      if (result.length === 0)
        return c.json({ error: true, message: 'Not found' }, 404);
      return c.json({ error: false, data: result[0] });
    });
     
    // [D] Delete
    app.delete('/api/student/:id', async (c) => {
      const id = Number(c.req.param('id'));
      const result = await db.delete(student).where(eq(student.id, id)).returning();
      if (result.length === 0)
        return c.json({ error: true, message: 'Not found' }, 404);
      return c.json({ error: false, message: `Deleted id ${id}` });
    });
     
    // Info about API
    app.get('/', async (c) => {
      return c.html(
        `<div><h1>Doc API</h1></div><a href="/api/student">/api/student.</a>`
      );
    });
     
    serve({ fetch: app.fetch, port: 5000 });
    console.log('✅ API running at http://localhost:5000');
    ```
    

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

## Test Teas !!

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

## Test Server

* Run Server:
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758983183054/9ebcdb61-cf12-4c90-9902-cfa54eff8359.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758983279922/95c81317-4bf2-4033-a67c-59d51c11c5fe.png align="center")
    
* Ah ERROR!, because we don’t have data into table
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758983347061/a706352e-2c93-4208-86a5-a837653fd935.png align="center")
    
* Click ctrl + c for stop the server
    
* and run the seed.js for add data into table
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758985131963/e9300e42-5533-4fd6-a21a-a873b495e82f.png align="center")
    
* run server
    
* and, yes successfully
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758985246123/0ce9f778-5553-416e-96b1-acf3a22cbb20.png align="center")
    

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

## Test CRUD API

* open API extension
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758985566174/bbc44dbd-d34c-443e-ab4c-4eb8bf8a0d12.png align="center")
    
* Click
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758985676061/79dcfaf6-56ee-4b3f-ab64-93499574620b.png align="center")
    

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

## Testing POST data to server

* Select `post`, fill in the url with the server address, select `body`, select `raw`, select `json`, and fill in with new student data
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758986137489/08aa87ab-b16f-4609-b82f-c974683bfc0c.png align="center")
    
* and post data with click `Send`
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758986405929/5620af8c-f8cb-4f76-beb3-18d454a86f5a.png align="center")
    
* see the result in server, before that you can reload the server page
    
* and error
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758987534552/cada75f3-a392-4539-8cd1-6eed3e8585a9.png align="center")
    
* I missed a comma, and it threw an error code, now i delete comma after address
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758988047473/7a2e2976-16b1-4293-abee-c0999f34a3ee.png align="center")
    
* Oke Successfully!
    

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

## Testing Read data

* Select `GET`, and fill the url with server address for read, we have 2 url for read, one for read all and more for read one data
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1759107397697/c7bf6008-b215-4e62-8e1f-2bf697debe7c.png align="center")
    
* read for all
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1759107887602/a460831f-f4dd-427c-ab8a-bc8bf149d84d.png align="center")
    
* read for one data, like read for all but adding data id at the end url
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1759108065236/cb6b7323-81c4-4298-ad02-0d94e085fc48.png align="center")
    

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

## Testing Update data

* choose put for update data, and for url same with read one data, and you can add new data in body select raw select json dan write new data like write for post
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1759108336099/2ca271eb-da13-4c15-8345-6b9c478cf69c.png align="center")
    
* this result after we update data, we will see the data that after being updated will be in last place
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1759108857948/26313ea1-f0f7-41e7-a63d-ebbb2ab13ec2.png align="center")
    

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

## Testing Delete data

* Select Delete and fill url like update or read more
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1759109078041/9b631b37-5f9a-46ea-ae31-970391c33336.png align="center")
    
* This result after we delete data, and we can see that the data with ID 2 was successfully deleted
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1759109140795/3fb2ee9c-c512-496c-aa67-e7966d183db2.png align="center")
    

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

### Closing

And that's it! 🎉 You've now successfully built a simple CRUD application. You’ve mastered the fundamentals: creating, reading, updating, and deleting data. The bridge is complete, and the data is flowing smoothly!

From here, you can try to:

* Add more features, such as a search function or pagination.
    
* Integrate with a frontend framework (like React or Vue) to build a full web application.
    
* Create a more engaging user interface.
    

**Thank you, Gemini, for following this entire journey!** The process of writing and arranging this article was made easier because you served as the editor, writing organizer, and idea *debugger*.

See you in the next project!

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
