Prisma – Next-generation ORM

Requisitos:

Conocimiento básico en API REST
Conocimiento básico de SQL
Node.js

npm client de su preferencia.

En este tutorial veremos como hacer un API REST TODO App con TypeScript, Prisma y esbuild.

⚠️ No necesitas previo conocimiento de ningun…

Requisitos:

  • Conocimiento básico en API REST
  • Conocimiento básico de SQL
  • Node.js
  • npm client de su preferencia.

En este tutorial veremos como hacer un API REST TODO App con TypeScript, Prisma y esbuild.

⚠️ No necesitas previo conocimiento de ninguna de estas tecnologías.

Que es Prisma?

Es un ORM de próxima generación con soporte para TypeScript con unas herramientas para facilitarnos la vida:

  • Prisma Client: Generador de consultas de tipo seguro y autogenerado que se adapta a sus datos.
  • Migraciones: Herramienta para crear y gestionar las migraciones de tu base de datos.
  • Prisma Studio: GUI client para tu base de datos.

👀 Para que no haya pierde en donde va cada cosa o si solo vienes a echar un vistazo rápido; te dejo el código en este repo.

Empezemos 🧑‍💻

Si estas usando VSCode puedes usar el plugin oficial de Prisma.

Instalemos nuestras dependencias

# yarn
$ yarn add -D prisma esbuild @types/node
$ yarn add @prisma/client

# npm
$ npm i -D prisma esbuild @types/node
$ npm i @prisma/client 

levantemos nuestro entorno de trabajo

# yarn
$ yarn prisma init

# npm
$ npx prisma init

Actualicemos nuestras variables de entorno. Para este tutorial practico usaremos SQLite pero puede revisar las que soporta Prisma.

# .env
DATABASE_URL="file:./database.sqlite"

Actualicemos nuestro schema.prisma

// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite" // <- usemos SQLite
  url      = env("DATABASE_URL")
}

Creamos nuestro builder con esbuild para trabajar con TypeScript.

Si no sabes como funciona esto igual luego deberías darte tiempo para leer mi blog esbuild – Desarrollo sin dolor

// esbuild.dev.js
import { spawn } from 'child_process'
import esbuild from 'esbuild'

let server;

const startServer = (message) => {
    if (server) server.kill('SIGINT')
    server = spawn('node', ['./dist/index.mjs'], { stdio: 'inherit' })
    console.log(`\n${message}\n`)
}

esbuild.build({
    entryPoints: ['./src/index.ts'],
    watch: { onRebuild: (err) => !err && startServer('Rebuilded') },
    bundle: true,
    minify: true,
    platform: 'node',
    format: 'esm',
    target: ['esnext'],
    external: ['/node_modules/*'],
    outfile: './dist/index.mjs',
})
    .then(() => startServer('Done 🚀'))
    .catch(() => process.exit(1))

Actualicemos nuestro package.json.

// package.json
{
  "name": "prisma",
  "version": "1.0.0",
  "main": "index.js",
  "author": "Ushieru Kokoran (https://ushieru.com/)",
  "license": "MIT",
  "type": "module", // <- soporte a mjs
  "scripts": {
    "dev": "node esbuild.dev.js" // <- script para desarrollo
  },
  "dependencies": {
    "@prisma/client": "^4.1.0",
    "@types/koa": "^2.13.5",
    "@types/node": "^18.0.6",
    "koa": "^2.13.4"
  },
  "devDependencies": {
    "esbuild": "^0.14.49",
    "prisma": "^4.1.0"
  }
}

Creemos el modelo de nuestras tareas. Si estas usando otra DB que no sea SQLite puede usar enums en el status. (defining-enums)

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

model Task {
  id          String   @id @default(cuid())
  name        String
  description String
  status      String   @default("OPEN") // OPEN, IN_PROGRESS, DONE
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
}

Ahora debemos cargar nuestros modelos a la base de datos.

# yarn
$ yarn prisma db push

# npm
$ npx prisma db push

terminal prisma 1

Generate Prisma Client…? Asi es, prisma genera los types de los objetos a partir de las tablas de la base de datos al vuelo. Es posible que VSCode no se de cuenta de este cambio así que hay que reiniciar el server de TypeScript.
Para eso abrimos la paleta de comandos y ejecutamos: TypeScript: Reset TS server.

Restet TS server

Creemos un cliente de prisma para tener acceso a nuestro ORM y su respectivo CRUD (Create, Read, Update, Delete).

// src/crudTask.ts
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

// Tenemos acceso a nuestro modelo task que es un mapeo exacto
// a nuestra tabla en la base de datos. Y con TypeScript tenemos
// el autocompletado para no cometer errores.

export const createTask = async (name: string, description: string) => {
    return await prisma.task.create({
        data: { name, description }
    })
}

export const readTasks = async () => {
    return await prisma.task.findMany()
}

export const readOneTask = async (id: string) => {
    return await prisma.task.findUnique({ where: { id } })
}

export const updateTask = async (id: string, name: string, description: string, status: 'OPEN' | 'IN_PROGRESS' | 'DONE') => {
    return await prisma.task.update({
        data: { name, description, status },
        where: { id }
    })
}

export const deleteTask = async (id: string) => {
    return await prisma.task.delete({ where: { id } })
}

Y ya lo tenemos 🎉🎉 Puedes envolverlo en cualquier backend que quieras en src/index.ts.

Si usas Next.js debes hacer unos cambios en la declaracion del cliente. Te dejo la Doc

Te muestro este pequeño ejemplo con Koa:

// src/index.ts
import Koa from 'koa';
import Router from 'koa-router';
import koaBody from 'koa-body';
import { createTask, readTasks, readOneTask, updateTask, deleteTask } from './crudTask'

const app = new Koa();

app.use(koaBody({ jsonLimit: '5kb' }));

const router = new Router();

router.get('/', (ctx) => ctx.body = 'Hello World');

router.post('/tasks', async (ctx) =>
    ctx.body = await createTask(ctx.request.body.name, ctx.request.body.description));

router.get('/tasks', async (ctx) =>
    ctx.body = await readTasks());

router.get('/tasks/:id', async (ctx) =>
    ctx.body = await readOneTask(ctx.params.id));

router.put('/tasks/:id', async (ctx) =>
    ctx.body = await updateTask(
        ctx.params.id,
        ctx.request.body.name,
        ctx.request.body.description,
        ctx.request.body.status
    ));

router.delete('/tasks/:id', async (ctx) =>
    ctx.body = await deleteTask(ctx.params.id));

app.use(router.routes());

app.listen(3000);

Y ya lo tenemos, vemos un ejemplo con Relaciones? cuéntame en los comentarios.

Y Happy Hacking 🎉👨‍💻


Print Share Comment Cite Upload Translate
APA
Ushieru Kokoran | Sciencx (2024-03-29T05:43:22+00:00) » Prisma – Next-generation ORM. Retrieved from https://www.scien.cx/2022/07/21/prisma-next-generation-orm/.
MLA
" » Prisma – Next-generation ORM." Ushieru Kokoran | Sciencx - Thursday July 21, 2022, https://www.scien.cx/2022/07/21/prisma-next-generation-orm/
HARVARD
Ushieru Kokoran | Sciencx Thursday July 21, 2022 » Prisma – Next-generation ORM., viewed 2024-03-29T05:43:22+00:00,<https://www.scien.cx/2022/07/21/prisma-next-generation-orm/>
VANCOUVER
Ushieru Kokoran | Sciencx - » Prisma – Next-generation ORM. [Internet]. [Accessed 2024-03-29T05:43:22+00:00]. Available from: https://www.scien.cx/2022/07/21/prisma-next-generation-orm/
CHICAGO
" » Prisma – Next-generation ORM." Ushieru Kokoran | Sciencx - Accessed 2024-03-29T05:43:22+00:00. https://www.scien.cx/2022/07/21/prisma-next-generation-orm/
IEEE
" » Prisma – Next-generation ORM." Ushieru Kokoran | Sciencx [Online]. Available: https://www.scien.cx/2022/07/21/prisma-next-generation-orm/. [Accessed: 2024-03-29T05:43:22+00:00]
rf:citation
» Prisma – Next-generation ORM | Ushieru Kokoran | Sciencx | https://www.scien.cx/2022/07/21/prisma-next-generation-orm/ | 2024-03-29T05:43:22+00:00
https://github.com/addpipe/simple-recorderjs-demo