DEV Community

Filipe Braga
Filipe Braga

Posted on • Updated on

API with Typescript + Nest + TypeORM + Postgres + Docker

In this blog post, I'll show you how to set up a project using TypeScript, Nest, Postgres, Docker and how to seed your database.

TypeScript is a statically typed language that is a strict syntactical superset of JavaScript. It offers improved type safety and tooling support, making it a popular choice for larger-scale projects.

Nest is a framework for building efficient, scalable Node.js server-side applications. It provides a structure and a range of features that make it easier to develop and test applications.

Postgres is a powerful open-source relational database management system that is well suited for complex data structures and large-scale data processing.

TypeORM is an open-source Object Relational Mapping (ORM) tool that provides a way to interact with relational databases such as MySQL, PostgreSQL, and SQLite. It helps you to write database-related code using object-oriented programming in TypeScript or JavaScript, instead of writing raw SQL statements. TypeORM offers a lot of features such as transaction management, database migrations, connection pooling, etc. that makes it easy to work with databases in your applications.

Docker is a containerization platform that makes it easier to deploy and run applications in different environments. We will launch a Postgres database and supporting service in docker.


Nest:
First, install nest-cli
npm i -g @nestjs/cli

Then, create a new project using the nest cli
nest new project-name

Choose: npm for package manager,

Next, enter in the project folder
cd project-name


PostgreSQL Database
Install pg
npm install pg --save


TypeORM
Install TypeOrm
npm install --save @nestjs/typeorm typeorm postgres


Open your project with your IDE

In the app.module.ts, add the connection to the databese with TypeOrmModule.forRoot():

// app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'localhost',
      port: 5432,
      username: 'root',
      password: 'password',
      database: 'postgres',
      entities: [`${__dirname}/typeorm/entities/*{.js,.ts}`],
      synchronize: true, // do not use in prod
    }),
  ],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

BTW: you can delete app.service and app.controller


Now, we should create our first module with nest cli:
nest g resource modules/users

choose REST API on terminal
select 'yes' to generate CRUD entry points


With the module created, we should now organize our project like this:

1) create some folders called: typeorm > database / entities / seeds
2) create data-source.ts, main.seed.ts and user.seed.ts
3) move the user entity to the entity folders

/src/typeorm
├── database
│   └── data-source.ts
├── seeds
│   └── main.seed.ts
└── entities
    └── user.entity.ts *(generated by the script)*
Enter fullscreen mode Exit fullscreen mode

insert the code bellow into the files:

// users.entity.ts
import { Column, CreateDateColumn, DeleteDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';

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

  @Column()
  name: string;

  @Column()
  email: string;

  @Column()
  active: boolean;

  @Column()
  birthday: Date;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @DeleteDateColumn()
  deletedAt: Date;
}
Enter fullscreen mode Exit fullscreen mode
// users.service.ts
import { Injectable } from '@nestjs/common';
import { User } from 'src/typeorm/entities/user.entity';
import { DataSource } from 'typeorm';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Injectable()
export class UsersService {
  constructor(private dataSource: DataSource) {}
  private userRepository = this.dataSource.getRepository(User);

  async create(createUserDto: CreateUserDto) {
    return this.userRepository.save(createUserDto);
  }

  async findAll(): Promise<User[]> {
    return this.userRepository.find();
  }

  async findOne(id: number) {
    return this.userRepository.findOneBy({ id });
  }

  async update(id: number, updateUserDto: UpdateUserDto) {
    let user = await this.findOne(id);
    user = { ...user, ...updateUserDto };
    return await this.userRepository.save(user);
  }

  async remove(id: number) {
    const user = await this.findOne(id);
    return await this.userRepository.softRemove(user);
  }
}
Enter fullscreen mode Exit fullscreen mode
// data-source.ts
import { DataSource, DataSourceOptions } from 'typeorm';

export const dataSourceOptions: DataSourceOptions = {
  type: 'postgres',
  host: 'localhost',
  port: 5432,
  username: 'root',
  password: 'password',
  database: 'postgres',
  entities: ['src/**/*.entity{.js,.ts}'],
};

export default new DataSource(dataSourceOptions);
Enter fullscreen mode Exit fullscreen mode
// main.seed.ts
import { DataSource } from 'typeorm';
import { dataSourceOptions } from '../database/data-source';
import { User } from '../entities/user.entity';

const dataSource = new DataSource(dataSourceOptions);
const userRepository = dataSource.getRepository(User);

async function connect() {
  try {
    if (dataSource.isInitialized) {
      await dataSource.destroy();
    }
    await dataSource.initialize();
    console.log('Data Source has been initialized!');
  } catch (err) {
    console.error('Error during Data Source connect', err);
  }
}

async function disconnect() {
  try {
    await dataSource.destroy();

    console.log('Data Source disconnected!');
  } catch (err) {
    console.error('Error during Data Source disconnect', err);
  }
}

async function seed() {
  const UserSeed = () => [
    {
      name: 'John Doe',
      email: 'john@doe.com',
      active: true,
      birthday: '1990-01-01',
    },
    {
      name: 'Jane Doe',
      email: 'jane@doe.com',
      active: false,
      birthday: '1990-01-31',
    },
    {
      name: 'Josh Doe',
      email: 'josh@doe.com',
      active: true,
      birthday: '2020-12-31',
    },
  ];

  await userRepository.save(UserSeed());
  console.log('created seeds');
}

async function runSeed() {
  await connect();
  console.log('connected');
  await seed();
  console.log('seed done');
  await disconnect();
  console.log('disconnected');
}

runSeed();

Enter fullscreen mode Exit fullscreen mode

Now, we should create our 'docker-compose.yml' file in the root folder, and then run sudo docker-compose up

! Make sure the Docker is running in your system !

version: '3.1'

services:
  db:
    image: postgres:14.2-alpine
    restart: always
    environment:
      POSTGRES_USER: "root"
      POSTGRES_PASSWORD: "password"
      POSTGRES_DB: "postgres"
    ports:
      - "5432:5432"
Enter fullscreen mode Exit fullscreen mode

Some useful docker commands:
sudo docker ps to list all containers
sudo docker stop my_container_name to stop a specific container


Now, add a script to package.json

// package.json
"seed":"npx ts-node src/typeorm/seeds/main.seed.ts",
Enter fullscreen mode Exit fullscreen mode

in a new terminal on the IDE run the code npm start to synchronize the database

kill the application, and then run the script npm run seed to populate the database


Its Done! now if you run npm start and send a GET request on localhost:3000/users, you shold get all the users from the seed.

Latest comments (4)

Collapse
 
sandross profile image
sandrobistene

So clear and well explained!
Gj bro!

Collapse
 
filbraga profile image
Filipe Braga

Thanks!!

Collapse
 
msennaa profile image
Matheus Sena

Amazing

Collapse
 
filbraga profile image
Filipe Braga

Thank you