{"id":224,"date":"2026-06-06T22:33:13","date_gmt":"2026-06-07T03:33:13","guid":{"rendered":"https:\/\/jeffsantillan.com\/blog\/?p=224"},"modified":"2026-06-07T00:04:17","modified_gmt":"2026-06-07T05:04:17","slug":"nestjs-aplicacion-de-matricula-a-curso","status":"publish","type":"post","link":"https:\/\/jeffsantillan.com\/blog\/nestjs-aplicacion-de-matricula-a-curso\/","title":{"rendered":"Nestjs aplicaci\u00f3n de matricula a curso &#8211; Parte I"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Es necesario crear el proyecto.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>nest new matricula-app<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"984\" src=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-31-1024x984.png\" alt=\"\" class=\"wp-image-225\" srcset=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-31-1024x984.png 1024w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-31-300x288.png 300w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-31-768x738.png 768w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-31.png 1062w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Luego vamos a utilizar Prisma para gestionar los datos.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En caso de no tener prisma es necesario instalarlo con npm<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install prisma @prisma\/client<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"446\" src=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-32-1024x446.png\" alt=\"\" class=\"wp-image-226\" srcset=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-32-1024x446.png 1024w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-32-300x131.png 300w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-32-768x335.png 768w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-32.png 1062w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Tenemos que estar dentro de la carpeta del proyecto para poder ejecutar el comando de prisma npx.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Vamos a definir el proveedor de base de datos que utilizare, para este ejercicio ser\u00e1 sqlite.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npx prisma init --datasource-provider sqlite<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"555\" src=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-33-1024x555.png\" alt=\"\" class=\"wp-image-227\" srcset=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-33-1024x555.png 1024w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-33-300x163.png 300w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-33-768x416.png 768w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-33.png 1194w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Tenemos que editar el archivo de <em>prisma\/schema.prisma<\/em> del proyecto con la estructura de datos a trabajar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Se presenta la definici\u00f3n de tablas solo con campos sencillos, sin relaciones a\u00fan<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>model Alumno {\n  id Int @id @default(autoincrement())\n  nombre String\n  apellido String\n  dni String @unique\n  email String @unique\n  createdAt Datetime @default(now())  \n}\n\nmodel Docente {\n  id Int @id @default(autoincrement())\n  nombre String\n  apellido String\n  dni String @unique\n  email String @unique    \n}\n\nmodel Curso {\n  id Int @id @default(autoincrement())\n  nombre String\n  codigo String @unique\n  creditos Int    \n}\n\nmodel Matricula {\n  id Int @id @default(autoincrement())\n  fecha Datetime @default(now())\n  estado String @default(\"ACTIVO\")\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Ahora vamos a establecer las FK y relaciones 1:n y n:1 con comentarios.<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>model Alumno {\n  id         Int         @id @default(autoincrement())\n  nombre     String\n  apellido   String\n  dni        String      @unique\n  email      String      @unique\n  createdAt  DateTime    @default(now())\n  matriculas Matricula&#91;] \/\/ Relaci\u00f3n 1:N \u2014 un alumno puede tener m\u00faltiples matr\u00edculas\n}\n\nmodel Docente {\n  id       Int     @id @default(autoincrement())\n  nombre   String\n  apellido String\n  dni      String  @unique\n  email    String  @unique\n  cursos   Curso&#91;] \/\/ Relaci\u00f3n 1:N \u2014 un docente puede dictar m\u00faltiples cursos\n}\n\nmodel Curso {\n  id         Int         @id @default(autoincrement())\n  nombre     String\n  codigo     String      @unique \/\/ C\u00f3digo \u00fanico del curso, ej: MAT101\n  creditos   Int\n  docenteId  Int         \/\/ FK \u2192 Docente (responsable del curso)\n  docente    Docente     @relation(fields: &#91;docenteId], references: &#91;id]) \/\/ Relaci\u00f3n N:1 \u2014 muchos cursos pueden tener un docente\n  matriculas Matricula&#91;] \/\/ Relaci\u00f3n 1:N \u2014 un curso puede tener m\u00faltiples alumnos matriculados\n}\n\nmodel Matricula {\n  id       Int      @id @default(autoincrement())\n  alumnoId Int      \/\/ FK \u2192 Alumno\n  cursoId  Int      \/\/ FK \u2192 Curso\n  fecha    DateTime @default(now())\n  estado   String   @default(\"ACTIVO\") \/\/ Estados posibles: ACTIVO | RETIRADO | APROBADO\n  alumno   Alumno   @relation(fields: &#91;alumnoId], references: &#91;id]) \/\/ Relaci\u00f3n N:1 \u2014 muchas matr\u00edculas pertenecen a un alumno\n  curso    Curso    @relation(fields: &#91;cursoId], references: &#91;id])   \/\/ Relaci\u00f3n N:1 \u2014 muchas matr\u00edculas pertenecen a un curso\n\n  @@unique(&#91;alumnoId, cursoId]) \/\/ Restricci\u00f3n: un alumno no puede matricularse dos veces al mismo curso\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Luego hay que ejecutar la migracion<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npx prisma migrate dev --name init<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"875\" src=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-34-1024x875.png\" alt=\"\" class=\"wp-image-230\" srcset=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-34-1024x875.png 1024w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-34-300x256.png 300w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-34-768x656.png 768w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-34.png 1194w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Migraci\u00f3n realizada se creo el archivo de base de datos sqlite -&gt; dev.db<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El nombre del archivo se defini\u00f3 en la <strong>DATABASE_URL<\/strong> del archivo <em>.env<\/em>, tambi\u00e9n vemos que ya se creo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Nota<\/strong>: <em>Prisma 7 ya trae instalado el dotenv, asi que no es necesario instalarlo directamente.<\/em><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"831\" height=\"124\" src=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-35.png\" alt=\"\" class=\"wp-image-232\" srcset=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-35.png 831w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-35-300x45.png 300w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-35-768x115.png 768w\" sizes=\"auto, (max-width: 831px) 100vw, 831px\" \/><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Se cre\u00f3 el archivo dev.db<\/li>\n\n\n\n<li>Se cre\u00f3 la migraci\u00f3n como historial de cambios prisma\/migrations\/20260607033831_init\/migration.sql<\/li>\n\n\n\n<li>Las 4 tablas han sido creadas.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Lo siguiente es generar el cliente de prisma con:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npx prisma generate<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"259\" src=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-36-1024x259.png\" alt=\"\" class=\"wp-image-235\" srcset=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-36-1024x259.png 1024w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-36-300x76.png 300w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-36-768x194.png 768w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-36.png 1194w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Ahora si necesitamos empezar a crear los recursos (resources) -&gt; module, service, controller, DTOs y entities<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Se va a utilizar el comando resource para crear todo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>g = generate<\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>nest g resource alumno\nnest g resource docente\nnest g resource curso\nnest g resource matricula<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Hara unas preguntas, responder con <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>What transport layer do you use? <\/em>&gt;&gt;<strong> REST API<\/strong><\/li>\n\n\n\n<li><em>Would you like to generate CRUD entry points?<\/em> &gt;&gt; <strong>Yes<\/strong><\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"654\" src=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-37-1024x654.png\" alt=\"\" class=\"wp-image-240\" srcset=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-37-1024x654.png 1024w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-37-300x191.png 300w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-37-768x490.png 768w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-37.png 1194w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Se genera todo.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"304\" height=\"338\" src=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-38.png\" alt=\"\" class=\"wp-image-242\" srcset=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-38.png 304w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-38-270x300.png 270w\" sizes=\"auto, (max-width: 304px) 100vw, 304px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Replicar para cada entidad \/ tabla.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Instalar adapter para integrar prisma con nestjs<\/strong> y lograr consultas a sqlite<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install @prisma\/adapter-better-sqlite3\nnpm install better-sqlite3\nnpm install --save-dev @types\/better-sqlite3<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"875\" src=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-39-1024x875.png\" alt=\"\" class=\"wp-image-245\" srcset=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-39-1024x875.png 1024w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-39-300x256.png 300w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-39-768x656.png 768w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-39.png 1194w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Luego tenemos que crear un archivo de module y service para prisma.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>nest generate module prisma\nnest generate service prisma<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">cada uno de estos archivos hay que editarlos.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">prisma\/prisma.service.ts<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>import { Injectable, OnModuleInit } from '@nestjs\/common';\n\nimport { PrismaClient } from '..\/..\/generated\/prisma\/client';\nimport { PrismaBetterSqlite3 } from '@prisma\/<strong>adapter-better-sqlite3<\/strong>';\n\n@Injectable()\nexport class PrismaService extends PrismaClient implements OnModuleInit {\n    \n    constructor(){\n        const adapter = new PrismaBetterSqlite3({ url: 'file:.\/dev.db' });\n        super({adapter})\n    }\n    \n    async onModuleInit() {\n        await this.$connect();\n    }\n\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">luego el archivo del module.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">prisma\/module.ts<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>import { Global, Module } from '@nestjs\/common';\nimport { PrismaService } from '.\/prisma.service';\n\n@Global()\n@Module({\n  providers: &#91;PrismaService],\n  exports: &#91;PrismaService]\n})\nexport class PrismaModule {}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">y tambi\u00e9n asegurarnos que el module este importando a nivel de la app.module.ts<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Si utilizaron los generadores el module se importara solo.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"460\" src=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-40-1024x460.png\" alt=\"\" class=\"wp-image-247\" srcset=\"https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-40-1024x460.png 1024w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-40-300x135.png 300w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-40-768x345.png 768w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-40-1300x584.png 1300w, https:\/\/jeffsantillan.com\/blog\/wp-content\/uploads\/2026\/06\/image-40.png 1309w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Luego hay que corregir un error de conflicto en las configuraciones de prisma por formato.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">prisma\/schema.prisma (Donde se definieron las tablas) hay que aclarar el formato del modulo (moduleFormat) como \u00abcjs\u00bb<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>generator client {\n  provider = \"prisma-client\"\n  output   = \"..\/generated\/prisma\"\n  <strong>moduleFormat = \"cjs\"<\/strong>\n}\n\ndatasource db {\n  provider = \"sqlite\"  \n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">luego ejecutar un npx prisma generate<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npx prisma generate<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Finalmente, ejecutar el proyecto para validar que todo esta funcionando.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm run start:dev<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Parte II &#8211; <a href=\"https:\/\/jeffsantillan.com\/blog\/nestjs-aplicacion-de-matricula-a-curso-parte-ii\/\" data-type=\"link\" data-id=\"https:\/\/jeffsantillan.com\/blog\/nestjs-aplicacion-de-matricula-a-curso-parte-ii\/\">Visitar<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Prisma.io &#8211; <a href=\"https:\/\/www.prisma.io\/\" data-type=\"link\" data-id=\"https:\/\/www.prisma.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">Enlace<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u00a1Saludos!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Es necesario crear el proyecto. Luego vamos a utilizar Prisma para gestionar los datos. En caso &hellip; <a title=\"Nestjs aplicaci\u00f3n de matricula a curso &#8211; Parte I\" class=\"hm-read-more\" href=\"https:\/\/jeffsantillan.com\/blog\/nestjs-aplicacion-de-matricula-a-curso\/\"><span class=\"screen-reader-text\">Nestjs aplicaci\u00f3n de matricula a curso &#8211; Parte I<\/span>Leer m\u00e1s<\/a><\/p>\n","protected":false},"author":2,"featured_media":211,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[48],"tags":[49,51],"class_list":["post-224","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-nestjs","tag-nestjs","tag-prisma"],"_links":{"self":[{"href":"https:\/\/jeffsantillan.com\/blog\/wp-json\/wp\/v2\/posts\/224","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jeffsantillan.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jeffsantillan.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jeffsantillan.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jeffsantillan.com\/blog\/wp-json\/wp\/v2\/comments?post=224"}],"version-history":[{"count":11,"href":"https:\/\/jeffsantillan.com\/blog\/wp-json\/wp\/v2\/posts\/224\/revisions"}],"predecessor-version":[{"id":255,"href":"https:\/\/jeffsantillan.com\/blog\/wp-json\/wp\/v2\/posts\/224\/revisions\/255"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jeffsantillan.com\/blog\/wp-json\/wp\/v2\/media\/211"}],"wp:attachment":[{"href":"https:\/\/jeffsantillan.com\/blog\/wp-json\/wp\/v2\/media?parent=224"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jeffsantillan.com\/blog\/wp-json\/wp\/v2\/categories?post=224"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jeffsantillan.com\/blog\/wp-json\/wp\/v2\/tags?post=224"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}