DEVELOPMENT by Pedro Resende

How to use NestJS with Turso Tech

a remote sqlite db

Post by Pedro Resende on the 28 of August of 2024 at 18:30

Tags: devdevelopmenttutorialsqlitetursonestjs

Turso Logo

This week, I've decided to spend some time investigating how hard it would be to use Nest.js with turso.tech.

What is turso.tech? It's a remote sqlite db or what they mention a SQLite for Production hosted in the cloud.

The free tier, it's quite interesting. It allows you to create up to 500 Databases, using a total of 9GB of storage, 1 billion row reads, 25 million written and up to three locations.

Let's start by installing Nest.js locally, I'm assuming you already have Node.js and NPM installed on your OS.

$ npm install -g @nestjs/cli
$ nest new nest-project

after running this command you should see something like this

⚡  We will scaffold your app in a few seconds..

? Which package manager would you ❤️  to use? npm
CREATE nest-project/.eslintrc.js (663 bytes)
CREATE nest-project/.prettierrc (51 bytes)
CREATE nest-project/README.md (4369 bytes)
CREATE nest-project/nest-cli.json (171 bytes)
CREATE nest-project/package.json (1951 bytes)
CREATE nest-project/tsconfig.build.json (97 bytes)
CREATE nest-project/tsconfig.json (546 bytes)
CREATE nest-project/src/app.controller.ts (274 bytes)
CREATE nest-project/src/app.module.ts (249 bytes)
CREATE nest-project/src/app.service.ts (142 bytes)
CREATE nest-project/src/main.ts (208 bytes)
CREATE nest-project/src/app.controller.spec.ts (617 bytes)
CREATE nest-project/test/jest-e2e.json (183 bytes)
CREATE nest-project/test/app.e2e-spec.ts (630 bytes)

✔ Installation in progress... ☕

🚀  Successfully created project nest-project
👉  Get started with the following commands:

$ cd nest-project
$ npm run start


                          Thanks for installing Nest 🙏
                 Please consider donating to our open collective
                        to help us maintain this package.


               🍷  Donate: https://opencollective.com/nest

let's verify that everything is in order, to do that you need to run

$ cd nest-project
$ npm run start

Open your browser on the address http://localhost:3000/ you should see the response Hello World!

Let's open a new terminal and run

$ nest g service prisma

after running this command you should see something like this

CREATE src/prisma/prisma.service.spec.ts (460 bytes)
CREATE src/prisma/prisma.service.ts (90 bytes)
UPDATE src/app.module.ts (321 bytes)

let's open the file src/prisma/prisma.service.ts and add the following content

import { Injectable } from '@nestjs/common';

@Injectable()
export class PrismaService {}

let's replace it with the following

import { Injectable } from '@nestjs/common';

import { PrismaClient } from '@prisma/client';
import { PrismaLibSQL } from '@prisma/adapter-libsql';
import { createClient } from '@libsql/client';

@Injectable()
export class PrismaService extends PrismaClient {
  constructor() {
    const libsql = createClient({
      url: `${process.env.TURSO_DATABASE_URL}`,
      authToken: `${process.env.TURSO_AUTH_TOKEN}`,
    });

    const adapter = new PrismaLibSQL(libsql);

    super({ adapter });
  }

  async onModuleInit() {
    await this.$connect();
  }
}

let's go back to the terminal and run

$ npm install @libsql/client @prisma/adapter-libsql @prisma/client
$ npm install prisma --save-dev
$ npx prisma
$ npx prisma init

let's open prisma/schema.prisma and replace it with the following

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["driverAdapters"]
}

datasource db {
  provider = "sqlite"
  url      = "file:./dev.db"
}

model User {
  userId    Int      @id @default(autoincrement())
  username  String   @unique
  password  String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

and run the command npx prisma generate

If you don't have an existing database, you can provision a database by running the following command:

$ turso db create turso-prisma-db

The above command will create a database in the closest region to your location.

Run the following command to retrieve your database's connection string:

$ turso db show turso-prisma-db

Next, create an authentication token that will allow you to connect to the database:

$ turso db tokens create turso-prisma-db

Update your .env file with the authentication token and connection string:

TURSO_AUTH_TOKEN="eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9..."
TURSO_DATABASE_URL="libsql://turso-prisma-db-user.turso.io"

Now let's create a user service, by running the following command

$ nest g service user

let's open the file src/user/user.service.ts and replace it with the following

import { Injectable } from '@nestjs/common';
import { User } from '@prisma/client';
import { PrismaService } from 'src/prisma/prisma.service';

@Injectable()
export class UserService {
  constructor(private prisma: PrismaService) {}

  async findAll() {
    return this.prisma.user.findMany();
  }

  async findOne(id: number) {
    return this.prisma.user.findUnique({
      where: { userId: id },
    });
  }

  async create(user: User) {
    return this.prisma.user.create({
      data: user,
    });
  }

  async update(id: number, user: User) {
    return this.prisma.user.update({
      where: { userId: id },
      data: user,
    });
  }

  async delete(id: number) {
    return this.prisma.user.delete({
      where: { userId: id },
    });
  }
}

let's open the file src/app.controller.ts and replace it with the following

import { Controller, Get, Post, Body, Patch, Param, Delete, NotFoundException } from '@nestjs/common';
import { UserService } from './user.service';
import { User } from '@prisma/client';

@Controller('users')
export class AppController {
  constructor(private readonly userService: UserService) {}

  @Get()
  findAll() {
    return this.userService.findAll();
  }

  @Get(':id')
  await findOne(@Param('id') id: string) {
    const user = await this.userService.findOne(+id);
    if (!user) {
      throw new NotFoundException(`User with id ${id} not found`);
    }

    return user;
  }

  @Post()
  create(@Body() user: User) {
    return this.userService.create(user);
  }

  @Patch(':id')
  update(@Param('id') id: string, @Body() user: User) {
    return this.userService.update(+id, user);
  }

  @Delete(':id')
  delete(@Param('id') id: string) {
    return this.userService.delete(+id);
  }
}

Now, let's generate a migration file using prisma migrate dev against a local SQLite database:

$ npx prisma migrate dev --name init

Apply the migration:

$ turso db shell turso-prisma-db < ./prisma/migrations/20230922132717_init/migration.sql

finally, let's run the application

$ npm run start:dev

and open your browser on the address http://localhost:3000/users you should see the response

[]

let's create a user by running the following command

$ curl -X POST -H "Content-Type: application/json" -d '{"username": "pedro", "password": "pedro"}' http://localhost:3000/users

you should see the response

{"userId":1,"username":"pedro","password":"pedro","createdAt":"2024-08-27T21:15:41.190Z","updatedAt":"2024-08-27T21:15:41.190Z"}

and open your browser on the address http://localhost:3000/users you should see the response

[
  {
    "userId": 1,
    "username": "pedro",
    "password": "pedro",
    "createdAt": "2024-08-27T21:15:41.190Z",
    "updatedAt": "2024-08-27T21:15:41.190Z"
  }
]

That's it.

Please let me know what you think about this tutorial, would you change anything or add something?