Configurar TypeORM para acceder a la base de datos (3ª parte de creación de una API REST con Express y TypeScript)

Publicado el 26 octubre 2022 por Daniel Rodríguez @analyticslane

En la publicación anterior de esta serie se ha visto una propuesta para organizar el código del proyecto. Una vez organizado el código es el momento de configurar una base de datos para persistir los datos. Para lo que se usará TypeORM. Un ORM (Object-relational mapping) para TypeScript mediante el cual se puede emplear una gran cantidad de motores de base de datos relacionales como MySQL, SQLite, PostgreSQL, Microsoft SQL Server u Oracle. Veamos cómo se puede configurar TypeORM en el proyecto.

¿Por qué usar un ORM?

Aunque en Node se puede acceder a la mayoría de las bases de datos sin la necesidad de un ORM. El uso de estas herramientas puede simplificar considerablemente el desarrollo de las aplicaciones. Especialmente si la base de datos puede cambiar durante el desarrollo del proyecto.

Un ORM no es más que una librería con la que se pueden mapear las estructuras de las bases de datos sobre estructuras lógicas de entidades, gracias a las cuales se puede simplificar el desarrollo de las aplicaciones. Así ya no sea necesario pensar en términos de tablas y sus relaciones, sino que en términos de objetos.

Instalación de TypeORM

La instalación de TypeORM se realiza como cualquier otro paquete de Node mediante el comando npm. En este caso también se debe instalar el controlador del motor de base de datos que se desee usar junto al ORM. A modo de ejemplo, para evitar la necesidad de configurar un motor de base de datos, vamos a usar SQLite en este proyecto. Así, el comando que se debe ejecutar en este caso es el siguiente

npm install typeorm sqlite3

Mediante el cual se instalará TypeORM y el controlador de SQLite 3.

Además de esto, debido a que TypeORM usa decoradores, es necesario modificar tres propiedades en el archivo tsconfig.json. En concreto se tiene que configurar las propiedades experimentalDecorators y emitDecoratorMetadata a verdadero, para se puedan usar decoradores, y strictPropertyInitialization a falso, para que al compilar las entidades no de un error de compilación porque los valores de las propiedades no están inicializados.

Configuración de TypeORM

Ahora que se ha instalado TypeORM junto al controlador de la base de datos podemos proceder a la configuración de este. Para ello se debe crear un archivo datsource.ts con el siguiente código.

import * as path from 'path';
import { DataSource } from 'typeorm';

let entities = ['dist/entities/**/*.js'];
if (path.extname(__filename) === '.ts') {
  entities = ['src/entities/**/*.ts'];
}

const datasource = new DataSource({
  type: 'sqlite',
  database: 'database.db',
  entities,
  synchronize: true,
});

export default datasource;

En este se crea una conexión a la base de datos con la clase DataSource, pasándole para ello un objeto con las opciones necesarias. Para el caso de SQLite solamente hay que indicar el tipo de driver type, el archivo en el que se encuentra la base de datos database, la carpeta donde se encuentra la definición de las entidades entities y una opción para que los cambios en las definiciones de las entidades se sincronicen de forma automática.

Nótese que al comienzo del archivo se define las entidades en función que la extensión del archivo se ts, esto es, cuando se está ejecutando el programa con ts-node. Algo que se hace para que el mismo código pueda funcionar tanto si el programa se ejecuta con ts-node en desarrollo como si se hace ya compilado con node.

Creación de una entidad con TypeORM

Ahora, una vez instalado y configurado TypeORM, se debe crear una entidad en la que almacenar datos. Posiblemente una de las más sencillas sea crear un usuario, para lo que se puede escribir en /src/entities el siguiente archivo como user.ts.

import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  firstName: string;

  @Column()
  lastName: string;
}

Nótese que la forma de crear la entidad es sencilla extremadamente sencilla. Simplemente se crea una clase y se usan los embellecedores de TypeORM para indicar que esta es una entidad (@Entity()) y cada uno de los tipos de datos que representan las propiedades (@PrimaryGeneratedColumn() o @Column()). En este ejemplo se crea una entidad llamada User con un id numérico autogenerado y dos columnas de texto firstName y lastName. Aunque se puede configurar, en la mayoría de los casos no es necesario prestar atención al tipo de dato necesario en la base de datos.

Conexión con la base de datos y creación de un registro

Ahora, para conectar con la base de datos solamente hay que importar e iniciar datasource. En el caso de que la conexión se inicie de forma correcta ya se podrá acceder a las entidades sin mayor problema. Para crear un nuevo registro solamente hay que crear un objeto y guardar éste en la fuente de datos. Esto es lo que se muestra en el siguiente ejemplo.

import datasource from './datasource';
import { User } from './entities/user';

// Conexión a la base de datos
datasource
  .initialize()
  .then(async () => {
    const user = new User();
    user.firstName = 'Nombre';
    user.lastName = 'Apellido';

    const result = await datasource.getRepository(User).save(user);
    console.log(result);
  })
  .catch((err) => {
    console.error('Error during Data Source initialization:', err);
  });

En este ejemplo se inicia la fuente de datos mediante la propiedad initialize(). En el caso de que se pueda realizar la conexión con la base de datos, se crea un nuevo registro y se guarda en la base de datos. El resultado de esto es un objeto que se puede ver por pantalla.

Por otro lado, si la conexión con la base de datos produjese un error, este se indicará por pantalla.

Comprobación de los cambios en la base de datos

Si se ejecuta el código anterior se creará un archivo database.db en la raíz del proyecto con una base de datos SQLlite. Al abrir este archivo con un programa se podrá ver el esquema de la base de datos y que el registro se ha agregado a la tabla.

Registro creado en la base de datos SQLite con TypeORM

En concreto, en el ejemplo la tabla user se ha creado con un campo id de tipo entorno no nulo y que es clave principal. Además de esto, se han creado dos campos de tipo varchar que tampoco pueden ser nulos.

Conclusiones

En esta tercera publicación de la serie se han visto los pasos necesarios para agregar y configurar TypeORM en el proyecto. La semana que viene se verá cómo crear nuestra primera API para agregar y eliminar usuarios.

Imagen de Tayeb MEZAHDIA en Pixabay