Drizzle ORM, SQLite and Nuxt JS - Getting Started
Tags: drizzle, orm, nuxt, vue
Published: 2023-08-07 01:56:43

###The Series

1. Drizzle ORM, SQLite and Nuxt JS - Getting Started
2. [Drizzle ORM SQLite and Nuxt - Integrating Nuxt Auth, Part 1](https://dev.to/aaronksaunders/drizzle-orm-sqlite-and-nuxt-integrating-nuxt-auth-part-1-534e)
3. [Drizzle ORM SQLite and Nuxt - Integrating Nuxt Auth, Part 2](https://dev.to/aaronksaunders/drizzle-orm-sqlite-and-nuxt-integrating-nuxt-auth-part-2-2ena)

---

##Overview
This is a companion post to support a [YouTube video tutorial]() that will walk you through integrating Drizzle ORM into a Nuxt JS project and creating the server API routes for CRUD actions on a user object. The routes are tested using Thunder Client, a lightweight REST API Client Extension for Visual Studio Code; similar to Postman.

[Drizzle](https://orm.drizzle.team/) is an Object Relational Mapper (ORM) for SQL databases. It is a lightweight and easy-to-use ORM that can map data between a relational database and an object-oriented programming language.

[Better SQLite](https://github.com/WiseLibs/better-sqlite3) is a wrapper around the SQLite database engine that provides a number of improvements over the standard SQLite API. One of those benefits is type safety, Better SQLite uses TypeScript to provide type safety for queries, which can help to prevent errors.

[Drizzle ORM Sqlite](https://github.com/drizzle-team/drizzle-orm/blob/main/drizzle-orm/src/sqlite-core/README.md)

##Video

{% youtube g6MDN9To9K4 %}

The next video will integrate the API routes into the app, introduce relations and put a clean UI on app using Tailwind

####Setup Nuxt app

```jsx
npx nuxi@latest init nuxt-drizzle-app
```

####Install drizzle packages and sqlite ORM package better-sqlite3

```jsx
cd nuxt-drizzle-app
npm i drizzle-orm better-sqlite3
```

####Install drizzle kit for migrations and for [Drizzle Studio](https://orm.drizzle.team/drizzle-studio/overview)

```jsx
npm i --save-dev drizzle-kit @types/better-sqlite3
```

####Create configuration file in project root for Drizzle `./drizzle.config.ts`

>See - [Configuration files – DrizzleORM](https://orm.drizzle.team/kit-docs/conf)

```jsx
import type { Config } from "drizzle-kit";

export default {
  schema: "./db/schema.ts",
  out: "./drizzle",
  driver: "better-sqlite",
  dbCredentials: {
    url: "./sqlite.db",
  },
} satisfies Config;
```

####Create basic schema file in `./db/schema.ts`

>See - [SQL schema declaration – DrizzleORM](https://orm.drizzle.team/docs/sql-schema-declaration)

```jsx
import { InferModel, sql } from "drizzle-orm";
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const users = sqliteTable("users", {
  id: integer("id").primaryKey(),
  firstName: text("first_name"),
  lastName: text("last_name"),
  age: integer("age"),
  createdAt: text("created_at").default(sql`CURRENT_TIMESTAMP`),
});

export type User = InferModel<typeof users>;
export type InsertUser = InferModel<typeof users, "insert">;
```

Above we have created a table and defined the types for the table that we can use in our application. Make sure you export the information that you will need in your application

####Drizzle Migration
Next we need to generate migration files which have the sql scripts information to create the tables in the new database.

```jsx
npm exec drizzle-kit generate:sqlite --out migrations --schema db/schema.ts
```

####Drizzle Push
Next we need to push the information from migration file created to the database. You can also just run the push command directly. 
> I believe there is a mechanism to allow for the migrations and push to happen automatically when you make changes to the schema file. I did not cover that in this first video and need to do some additional research on the topic

```jsx
npm exec drizzle-kit push:sqlite
```

####Drizzle Studio
We can now start Drizzle Studio to see the database and add a dummy record for us to query. Drizzle Studio is a graphical UI for you to view and manipulate your database

```jsx
npm exec drizzle-kit studio
```

###Integrating With Nuxt

####Creating a Service to Interact With Database
create a service in the nuxt application `./server/api/sqlite-service-ts`

- database connection - [BetterSqlite3 – DrizzleORM](https://orm.drizzle.team/docs/installation-and-db-connection/sqlite/better-sqlite3)

```jsx
import { drizzle, BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
import Database from 'better-sqlite3';
 
export const sqlite = new Database('sqlite.db');
export const db: BetterSQLite3Database = drizzle(sqlite);
```

We are going to create the API routes for the application and they will support the CRUD actions on the `user` object.

```
GET - http://localhost:3000/api/users
GET - http://localhost:3000/api/users/[id]
PUT - http://localhost:3000/api/users/[id]
POST - http://localhost:3000/api/users
DELETE - http://localhost:3000/api/users/[id]
```

This is what your directory in your project will look like after all of the routes are added

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ew9579tk6j5fheqdpe0k.png)


####Get All Users
Create a new server api route `./server/api/users.get.ts`

```jsx
import { users } from "../../db/schema";
import { db } from "../sqlite-service";

export default defineEventHandler(async () => {
  try {
    const usersResp = db.select().from(users).all();
    return { "users" : usersResp}
  } catch (e: any) {
    throw createError({
      statusCode: 400,
      statusMessage: e.message,
    });
  }
});
```

####Add User
Create a new server api route `./server/api/users.post.ts`, notice the user of the http method `post` in the name to ensures that this route will only with with that method.

This is a bit different from the get user because here we need the body of the http request to get the information needed to add the user to the database
```jsx
import { users, InsertUser } from "@/db/schema";
import { db } from "@/server/sqlite-service";

export default defineEventHandler(async (event) => {
  try {
    const body = await readBody(event);
    const newUser: InsertUser = {
      ...body
    }
    const result = db.insert(users).values(newUser).run();
    return { newUser : result}
  } catch (e: any) {
    throw createError({
      statusCode: 400,
      statusMessage: e.message,
    });
  }
});

```

####Get User By User Id
Create a new server api route `./server/api/users/[id].get.ts`, notice the use of the http method `get` in the name to ensures that this route will only with with that method.

Also we are using a `[id]` in the file name, this lets us know that the `id` parameter will be available in the function

```tsx
import { users } from "../../../db/schema";
import { db } from "../../sqlite-service";
import { eq } from "drizzle-orm";
export default defineEventHandler(async (event) => {
  try {
    // get id as function parameter from route params
    const userId = event.context.params?.id as string;
    const usersResp = db
      .select()
      .from(users)
      .where(eq(users.id, parseInt(userId)))
      .get();
    return { user: usersResp };
  } catch (e: any) {
    throw createError({
      statusCode: 400,
      statusMessage: e.message,
    });
  }
});

```

####Delete User By User Id
Create a new server api route `./server/api/users/[id].delete.ts`, notice the use of the http method `delete` in the name to ensures that this route will only with with that method.

Also we are using a `[id]` in the file name, this lets us know that the `id` parameter will be available in the function

```tsx
import { users } from "../../../db/schema";
import { db } from "../../sqlite-service";
import { eq } from "drizzle-orm";
export default defineEventHandler(async (event) => {
  try {
    const userId = event.context.params?.id as string;
    const usersResp = db
      .delete(users)
      .where(eq(users.id, parseInt(userId)))
      .run();
    return { user: usersResp };
  } catch (e: any) {
    throw createError({
      statusCode: 400,
      statusMessage: e.message,
    });
  }
});

```
In this route we introduced the use of `where` and `eq` to help us find the proper user to delete.

####Update User By User Id
Create a new server api route `./server/api/users/[id].put.ts`, notice the use of the http method `delete` in the name to ensures that this route will only with with that method.

Also we are using a `[id]` in the file name, this lets us know that the `id` parameter will be available in the function

And this method will also be passed a `body` in the http request to get the information needed to update the user to the database.

```tsx
import { InsertUser, users } from "../../../db/schema";
import { db } from "../../sqlite-service";
import { eq } from "drizzle-orm";
export default defineEventHandler(async (event) => {
  try {
    const userId = event.context.params?.id as string;
    const body = await readBody(event);
    const editUser: InsertUser = {
      ...body
    }
    const usersResp = db
      .update(users)
      .set(editUser)
      .where(eq(users.id, parseInt(userId)))
      .run();
    return { user: usersResp };
  } catch (e: any) {
    throw createError({
      statusCode: 400,
      statusMessage: e.message,
    });
  }
});
```

##Testing
In this first part of the video series I did all of my testing using the Thunder Client for VS Code, It has the same functionality of any Postman like REST API tool.

The [next part in the video series will cover integrating the Nuxt Auth](https://youtu.be/pQtFvO4ks8o) using Drizzle ORM with SQLite.



##Links
- Drizzle Quick Start - https://orm.drizzle.team/docs/quick-start
- Drizzle Kit - https://orm.drizzle.team/kit-docs/overview
- Drizzle ORM Sqlite - https://github.com/drizzle-team/drizzle-orm/blob/main/drizzle-orm/src/sqlite-core/README.md
- Better Sqlite 3 - https://github.com/WiseLibs/better-sqlite3

##Social Media 
- Twitter - https://twitter.com/aaronksaunders
- Facebook - https://www.facebook.com/ClearlyInnovative
- Instagram - https://www.instagram.com/aaronksaunders
- Dev.to - https://dev.to/aaronksaunders
- YouTube - https://www.youtube.com/@Aaronsaundersci