- 1. API with NestJS #1. Controllers, routing and the module structure
- 2. API with NestJS #2. Setting up a PostgreSQL database with TypeORM
- 3. API with NestJS #3. Authenticating users with bcrypt, Passport, JWT, and cookies
- 4. API with NestJS #4. Error handling and data validation
- 5. API with NestJS #5. Serializing the response with interceptors
- 6. API with NestJS #6. Looking into dependency injection and modules
- 7. API with NestJS #7. Creating relationships with Postgres and TypeORM
- 8. API with NestJS #8. Writing unit tests
- 9. API with NestJS #9. Testing services and controllers with integration tests
- 10. API with NestJS #10. Uploading public files to Amazon S3
- 11. API with NestJS #11. Managing private files with Amazon S3
- 12. API with NestJS #12. Introduction to Elasticsearch
- 13. API with NestJS #13. Implementing refresh tokens using JWT
- 14. API with NestJS #14. Improving performance of our Postgres database with indexes
- 15. API with NestJS #15. Defining transactions with PostgreSQL and TypeORM
- 16. API with NestJS #16. Using the array data type with PostgreSQL and TypeORM
- 17. API with NestJS #17. Offset and keyset pagination with PostgreSQL and TypeORM
- 18. API with NestJS #18. Exploring the idea of microservices
- 19. API with NestJS #19. Using RabbitMQ to communicate with microservices
- 20. API with NestJS #20. Communicating with microservices using the gRPC framework
- 21. API with NestJS #21. An introduction to CQRS
- 22. API with NestJS #22. Storing JSON with PostgreSQL and TypeORM
- 23. API with NestJS #23. Implementing in-memory cache to increase the performance
- 24. API with NestJS #24. Cache with Redis. Running the app in a Node.js cluster
- 25. API with NestJS #25. Sending scheduled emails with cron and Nodemailer
- 26. API with NestJS #26. Real-time chat with WebSockets
- 27. API with NestJS #27. Introduction to GraphQL. Queries, mutations, and authentication
- 28. API with NestJS #28. Dealing in the N + 1 problem in GraphQL
- 29. API with NestJS #29. Real-time updates with GraphQL subscriptions
- 30. API with NestJS #30. Scalar types in GraphQL
- 31. API with NestJS #31. Two-factor authentication
- 32. API with NestJS #32. Introduction to Prisma with PostgreSQL
- 33. API with NestJS #33. Managing PostgreSQL relationships with Prisma
- 34. API with NestJS #34. Handling CPU-intensive tasks with queues
- 35. API with NestJS #35. Using server-side sessions instead of JSON Web Tokens
- 36. API with NestJS #36. Introduction to Stripe with React
- 37. API with NestJS #37. Using Stripe to save credit cards for future use
- 38. API with NestJS #38. Setting up recurring payments via subscriptions with Stripe
- 39. API with NestJS #39. Reacting to Stripe events with webhooks
- 40. API with NestJS #40. Confirming the email address
- 41. API with NestJS #41. Verifying phone numbers and sending SMS messages with Twilio
- 42. API with NestJS #42. Authenticating users with Google
- 43. API with NestJS #43. Introduction to MongoDB
- 44. API with NestJS #44. Implementing relationships with MongoDB
- 45. API with NestJS #45. Virtual properties with MongoDB and Mongoose
- 46. API with NestJS #46. Managing transactions with MongoDB and Mongoose
- 47. API with NestJS #47. Implementing pagination with MongoDB and Mongoose
- 48. API with NestJS #48. Definining indexes with MongoDB and Mongoose
- 49. API with NestJS #49. Updating with PUT and PATCH with MongoDB and Mongoose
- 50. API with NestJS #50. Introduction to logging with the built-in logger and TypeORM
- 51. API with NestJS #51. Health checks with Terminus and Datadog
- 52. API with NestJS #52. Generating documentation with Compodoc and JSDoc
- 53. API with NestJS #53. Implementing soft deletes with PostgreSQL and TypeORM
- 54. API with NestJS #54. Storing files inside a PostgreSQL database
- 55. API with NestJS #55. Uploading files to the server
- 56. API with NestJS #56. Authorization with roles and claims
- 57. API with NestJS #57. Composing classes with the mixin pattern
- 58. API with NestJS #58. Using ETag to implement cache and save bandwidth
- 59. API with NestJS #59. Introduction to a monorepo with Lerna and Yarn workspaces
- 60. API with NestJS #60. The OpenAPI specification and Swagger
- 61. API with NestJS #61. Dealing with circular dependencies
- 62. API with NestJS #62. Introduction to MikroORM with PostgreSQL
- 63. API with NestJS #63. Relationships with PostgreSQL and MikroORM
- 64. API with NestJS #64. Transactions with PostgreSQL and MikroORM
- 65. API with NestJS #65. Implementing soft deletes using MikroORM and filters
- 66. API with NestJS #66. Improving PostgreSQL performance with indexes using MikroORM
- 67. API with NestJS #67. Migrating to TypeORM 0.3
- 68. API with NestJS #68. Interacting with the application through REPL
- 69. API with NestJS #69. Database migrations with TypeORM
- 70. API with NestJS #70. Defining dynamic modules
- 71. API with NestJS #71. Introduction to feature flags
- 72. API with NestJS #72. Working with PostgreSQL using raw SQL queries
- 73. API with NestJS #73. One-to-one relationships with raw SQL queries
- 74. API with NestJS #74. Designing many-to-one relationships using raw SQL queries
- 75. API with NestJS #75. Many-to-many relationships using raw SQL queries
- 76. API with NestJS #76. Working with transactions using raw SQL queries
- 77. API with NestJS #77. Offset and keyset pagination with raw SQL queries
- 78. API with NestJS #78. Generating statistics using aggregate functions in raw SQL
- 79. API with NestJS #79. Implementing searching with pattern matching and raw SQL
- 80. API with NestJS #80. Updating entities with PUT and PATCH using raw SQL queries
- 81. API with NestJS #81. Soft deletes with raw SQL queries
- 82. API with NestJS #82. Introduction to indexes with raw SQL queries
- 83. API with NestJS #83. Text search with tsvector and raw SQL
- 84. API with NestJS #84. Implementing filtering using subqueries with raw SQL
- 85. API with NestJS #85. Defining constraints with raw SQL
- 86. API with NestJS #86. Logging with the built-in logger when using raw SQL
- 87. API with NestJS #87. Writing unit tests in a project with raw SQL
- 88. API with NestJS #88. Testing a project with raw SQL using integration tests
- 89. API with NestJS #89. Replacing Express with Fastify
- 90. API with NestJS #90. Using various types of SQL joins
- 91. API with NestJS #91. Dockerizing a NestJS API with Docker Compose
- 92. API with NestJS #92. Increasing the developer experience with Docker Compose
- 93. API with NestJS #93. Deploying a NestJS app with Amazon ECS and RDS
- 94. API with NestJS #94. Deploying multiple instances on AWS with a load balancer
- 95. API with NestJS #95. CI/CD with Amazon ECS and GitHub Actions
- 96. API with NestJS #96. Running unit tests with CI/CD and GitHub Actions
- 97. API with NestJS #97. Introduction to managing logs with Amazon CloudWatch
- 98. API with NestJS #98. Health checks with Terminus and Amazon ECS
- 99. API with NestJS #99. Scaling the number of application instances with Amazon ECS
- 100. API with NestJS #100. The HTTPS protocol with Route 53 and AWS Certificate Manager
- 101. API with NestJS #101. Managing sensitive data using the AWS Secrets Manager
- 102. API with NestJS #102. Writing unit tests with Prisma
- 103. API with NestJS #103. Integration tests with Prisma
- 104. API with NestJS #104. Writing transactions with Prisma
- 105. API with NestJS #105. Implementing soft deletes with Prisma and middleware
- 106. API with NestJS #106. Improving performance through indexes with Prisma
- 107. API with NestJS #107. Offset and keyset pagination with Prisma
- 108. API with NestJS #108. Date and time with Prisma and PostgreSQL
- 109. API with NestJS #109. Arrays with PostgreSQL and Prisma
- 110. API with NestJS #110. Managing JSON data with PostgreSQL and Prisma
- 111. API with NestJS #111. Constraints with PostgreSQL and Prisma
- 112. API with NestJS #112. Serializing the response with Prisma
- 113. API with NestJS #113. Logging with Prisma
- 114. API with NestJS #114. Modifying data using PUT and PATCH methods with Prisma
- 115. API with NestJS #115. Database migrations with Prisma
- 116. API with NestJS #116. REST API versioning
- 117. API with NestJS #117. CORS – Cross-Origin Resource Sharing
- 118. API with NestJS #118. Uploading and streaming videos
- 119. API with NestJS #119. Type-safe SQL queries with Kysely and PostgreSQL
- 120. API with NestJS #120. One-to-one relationships with the Kysely query builder
- 121. API with NestJS #121. Many-to-one relationships with PostgreSQL and Kysely
- 122. API with NestJS #122. Many-to-many relationships with Kysely and PostgreSQL
- 123. API with NestJS #123. SQL transactions with Kysely
- 124. API with NestJS #124. Handling SQL constraints with Kysely
- 125. API with NestJS #125. Offset and keyset pagination with Kysely
- 126. API with NestJS #126. Improving the database performance with indexes and Kysely
- 127. API with NestJS #127. Arrays with PostgreSQL and Kysely
- 128. API with NestJS #128. Managing JSON data with PostgreSQL and Kysely
- 129. API with NestJS #129. Implementing soft deletes with SQL and Kysely
- 130. API with NestJS #130. Avoiding storing sensitive information in API logs
- 131. API with NestJS #131. Unit tests with PostgreSQL and Kysely
- 132. API with NestJS #132. Handling date and time in PostgreSQL with Kysely
- 133. API with NestJS #133. Introducing database normalization with PostgreSQL and Prisma
- 134. API with NestJS #134. Aggregating statistics with PostgreSQL and Prisma
- 135. API with NestJS #135. Referential actions and foreign keys in PostgreSQL with Prisma
- 136. API with NestJS #136. Raw SQL queries with Prisma and PostgreSQL range types
- 137. API with NestJS #137. Recursive relationships with Prisma and PostgreSQL
- 138. API with NestJS #138. Filtering records with Prisma
- 139. API with NestJS #139. Using UUID as primary keys with Prisma and PostgreSQL
- 140. API with NestJS #140. Using multiple PostgreSQL schemas with Prisma
- 141. API with NestJS #141. Getting distinct records with Prisma and PostgreSQL
- 142. API with NestJS #142. A video chat with WebRTC and React
- 143. API with NestJS #143. Optimizing queries with views using PostgreSQL and Kysely
- 144. API with NestJS #144. Creating CLI applications with the Nest Commander
- 145. API with NestJS #145. Securing applications with Helmet
- 146. API with NestJS #146. Polymorphic associations with PostgreSQL and Prisma
- 147. API with NestJS #147. The data types to store money with PostgreSQL and Prisma
- 148. API with NestJS #148. Understanding the injection scopes
- 149. API with NestJS #149. Introduction to the Drizzle ORM with PostgreSQL
- 150. API with NestJS #150. One-to-one relationships with the Drizzle ORM
- 151. API with NestJS #151. Implementing many-to-one relationships with Drizzle ORM
- 152. API with NestJS #152. SQL constraints with the Drizzle ORM
- 153. API with NestJS #153. SQL transactions with the Drizzle ORM
- 154. API with NestJS #154. Many-to-many relationships with Drizzle ORM and PostgreSQL
- 155. API with NestJS #155. Offset and keyset pagination with the Drizzle ORM
- 156. API with NestJS #156. Arrays with PostgreSQL and the Drizzle ORM
- 157. API with NestJS #157. Handling JSON data with PostgreSQL and the Drizzle ORM
- 158. API with NestJS #158. Soft deletes with the Drizzle ORM
- 159. API with NestJS #159. Date and time with PostgreSQL and the Drizzle ORM
- 160. API with NestJS #160. Using views with the Drizzle ORM and PostgreSQL
- 161. API with NestJS #161. Generated columns with the Drizzle ORM and PostgreSQL
- 162. API with NestJS #162. Identity columns with the Drizzle ORM and PostgreSQL
- 163. API with NestJS #163. Full-text search with the Drizzle ORM and PostgreSQL
- 164. API with NestJS #164. Improving the performance with indexes using Drizzle ORM
- 165. API with NestJS #165. Time intervals with the Drizzle ORM and PostgreSQL
- 166. API with NestJS #166. Logging with the Drizzle ORM
- 167. API with NestJS #167. Unit tests with the Drizzle ORM
- 168. API with NestJS #168. Integration tests with the Drizzle ORM
- 169. API with NestJS #169. Unique IDs with UUIDs using Drizzle ORM and PostgreSQL
- 170. API with NestJS #170. Polymorphic associations with PostgreSQL and Drizzle ORM
- 171. API with NestJS #171. Recursive relationships with Drizzle ORM and PostgreSQL
- 172. API with NestJS #172. Database normalization with Drizzle ORM and PostgreSQL
- 173. API with NestJS #173. Storing money with Drizzle ORM and PostgreSQL
- 174. API with NestJS #174. Multiple PostgreSQL schemas with Drizzle ORM
- 175. API with NestJS #175. PUT and PATCH requests with PostgreSQL and Drizzle ORM
- 176. API with NestJS #176. Database migrations with the Drizzle ORM
- 177. API with NestJS #177. Response serialization with the Drizzle ORM
- 178. API with NestJS #178. Storing files inside of a PostgreSQL database with Drizzle
- 179. API with NestJS #179. Pattern matching search with Drizzle ORM and PostgreSQL
- 180. API with NestJS #180. Organizing Drizzle ORM schema with PostgreSQL
The next important thing when learning how to create an API is how to store the data. In this article, we look into how to do so with PostgreSQL and NestJS. To make the managing of a database more convenient, we use an Object-relational mapping (ORM) tool called TypeORM. To have an even better understanding, we also look into some SQL queries. By doing so, we can grasp what advantages ORM gives us.
You can find all of the below code in this repository.
Creating a PostgreSQL database
The most straightforward way of kickstarting our development with a Postgres database is to use docker.
Here, we use the same setup as in the TypesScript Express series.
The first thing to do is to install Docker and Docker Compose. Now, we need to create a docker-compose file and run it.
docker-compose.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
version: "3" services: postgres: container_name: postgres image: postgres:latest ports: - "5432:5432" volumes: - /data/postgres:/data/postgres env_file: - docker.env networks: - postgres pgadmin: links: - postgres:postgres container_name: pgadmin image: dpage/pgadmin4 ports: - "8080:80" volumes: - /data/pgadmin:/root/.pgadmin env_file: - docker.env networks: - postgres networks: postgres: driver: bridge |
The useful thing about the above configuration is that it also starts a pgAdmin console. It gives us the possibility to view the state of our database and interact with it.
To provide credentials used by our Docker containers, we need to create the docker.env file. You might want to skip committing it by adding it to your .gitignore.
docker.env
1 2 3 4 5 |
POSTGRES_USER=admin POSTGRES_PASSWORD=admin POSTGRES_DB=nestjs PGADMIN_DEFAULT_EMAIL=admin@admin.com PGADMIN_DEFAULT_PASSWORD=admin |
Once all of the above is set up, we need to start the containers:
1 |
docker-compose up |
Environment variables
A crucial thing to running our application is to set up environment variables. By using them to hold configuration data, we can make it easily configurable. Also, it is easier to keep sensitive data from being committed to a repository.
In the Express Typescript series, we use a library called dotenv to inject our variables. In NestJS, we have a ConfigModule that we can use in our application. It uses dotenv under the hood.
1 |
npm install @nestjs/config |
app.module.ts
1 2 3 4 5 6 7 8 9 10 |
import { Module } from '@nestjs/common'; import { PostsModule } from './posts/posts.module'; import { ConfigModule } from '@nestjs/config'; @Module({ imports: [PostsModule, ConfigModule.forRoot()], controllers: [], providers: [], }) export class AppModule {} |
As soon as we create a .env file at the root of our application, NestJS injects them into a ConfigSerivice that we will use soon.
.env
1 2 3 4 5 6 |
POSTGRES_HOST=localhost POSTGRES_PORT=5432 POSTGRES_USER=admin POSTGRES_PASSWORD=admin POSTGRES_DB=nestjs PORT=5000 |
Validating environment variables
It is an excellent idea to verify our environment variables before running the application. In the TypeScript Express series, we’ve used a library called envalid.
The ConfigModule built into NestJS supports @hapi/joi that we can use to define a validation schema.
1 |
npm install @hapi/joi @types/hapi__joi |
app.module.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import { Module } from '@nestjs/common'; import { PostsModule } from './posts/posts.module'; import { ConfigModule } from '@nestjs/config'; import * as Joi from '@hapi/joi'; @Module({ imports: [ PostsModule, ConfigModule.forRoot({ validationSchema: Joi.object({ POSTGRES_HOST: Joi.string().required(), POSTGRES_PORT: Joi.number().required(), POSTGRES_USER: Joi.string().required(), POSTGRES_PASSWORD: Joi.string().required(), POSTGRES_DB: Joi.string().required(), PORT: Joi.number(), }) }) ], controllers: [], providers: [], }) export class AppModule {} |
Connecting a NestJS application with PostgreSQL
A first thing to do once we have our database running is to define a connection between our application and the database. To do so, we use TypeOrmModule.
1 |
npm install @nestjs/typeorm typeorm pg |
To keep our code clean, I suggest creating a database module.
database.module.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { ConfigModule, ConfigService } from '@nestjs/config'; @Module({ imports: [ TypeOrmModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (configService: ConfigService) => ({ type: 'postgres', host: configService.get('POSTGRES_HOST'), port: configService.get('POSTGRES_PORT'), username: configService.get('POSTGRES_USER'), password: configService.get('POSTGRES_PASSWORD'), database: configService.get('POSTGRES_DB'), entities: [ __dirname + '/../**/*.entity.ts', ], synchronize: true, }) }), ], }) export class DatabaseModule {} |
The synchronize flag above is very important. We will elaborate on it a lot later
An essential thing above is that we use the ConfigModule and ConfigService. The useFactory method can access the environment variables thanks to providing the imports and inject arrays. We elaborate on these mechanisms in the upcoming parts of this series.
Now, we need to import our DatabaseModule.
app.module.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import { Module } from '@nestjs/common'; import { PostsModule } from './posts/posts.module'; import { ConfigModule } from '@nestjs/config'; import * as Joi from '@hapi/joi'; import { DatabaseModule } from './database/database.module'; @Module({ imports: [ PostsModule, ConfigModule.forRoot({ validationSchema: Joi.object({ POSTGRES_HOST: Joi.string().required(), POSTGRES_PORT: Joi.number().required(), POSTGRES_USER: Joi.string().required(), POSTGRES_PASSWORD: Joi.string().required(), POSTGRES_DB: Joi.string().required(), PORT: Joi.number(), }) }), DatabaseModule, ], controllers: [], providers: [], }) export class AppModule {} |
Entities
The most crucial concept to grasp when using TypeORM is the entity. It is a class that maps to a database table. To create it, we use the @Entity() decorator.
post.entity.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; @Entity() class Post { @PrimaryGeneratedColumn() public id: number; @Column() public title: string; @Column() public content: string; } export default Post; |
A neat thing about TypeORM is that it integrates well with TypeScript because it is written in it. To define our columns, we can use various decorators.
@PrimaryGeneratedColumn()
A primary key is a column used to identify a row uniquely in a table. Although we might use an existing column and make it primary, we usually create an id column. By choosing PrimaryGeneratedColumn from TypeORM, we create an integer primary column that has a value generated automatically.
@Column()
The @Column() decorator marks a property as a column. When using it, we have two possible approaches.
The first approach is not to pass the column type explicitly. When we do it, TypeORM figures out the column using our TypeScript types. It is possible because NestJS uses reflect-metadata under the hood.
The second approach would be to pass the type of column explicitly, for example, by using @Column('text'). The available column types differ between databases like MySQL and Postgres. You can look them up in the TypeORM documentation.
It is a proper moment to discuss different ways to store strings in Postgres. Relying on TypeORM to figure out the type of a string column results in the “character varying” type, also called varchar.
Varchar is very similar to a text type of a column but gives us a possibility to limit the length of a string. Both types are the same performance-wise.
SQL query
In pgAdmin, we can check a query equivalent to what TypeORM did for us under the hood.
1 2 3 4 5 6 7 |
CREATE TABLE public.post ( id integer NOT NULL DEFAULT nextval('post_id_seq'::regclass), title character varying COLLATE pg_catalog."default" NOT NULL, content character varying COLLATE pg_catalog."default" NOT NULL, CONSTRAINT "PK_be5fda3aac270b134ff9c21cdee" PRIMARY KEY (id) ) |
There are a few interesting things to notice above
Using @PrimaryGeneratedColumn() results in having an int column. It defaults to the return value of a nextval function that returns unique ids. An alternative would be to use a serial type instead and would make the query shorter, but it works the same under the hood.
Our entity has varchar columns that use COLLATE. Collation is used to specify the sort order and character classification. To see our default collation, we can run this query:
1 |
SHOW LC_COLLATE |
en_US.utf8
The above value is defined in a query that was used to create our database. It is UTF8 and English by default.
1 2 3 4 5 6 7 8 |
CREATE DATABASE nestjs WITH OWNER = admin ENCODING = 'UTF8' LC_COLLATE = 'en_US.utf8' LC_CTYPE = 'en_US.utf8' TABLESPACE = pg_default CONNECTION LIMIT = -1; |
Also, our CREATE TABLE query puts a constraint on our ids so that they are always unique.
PK_be5fda3aac270b134ff9c21cdee is a name of the above constraint and was generated
Repositories
With repositories, we can manage a particular entity. A repository has multiple functions to interact with entities. To access it, we use the TypeOrmModule again.
posts.module.ts
1 2 3 4 5 6 7 8 9 10 11 12 |
import { Module } from '@nestjs/common'; import PostsController from './posts.controller'; import PostsService from './posts.service'; import Post from './post.entity'; import { TypeOrmModule } from '@nestjs/typeorm'; @Module({ imports: [TypeOrmModule.forFeature([Post])], controllers: [PostsController], providers: [PostsService], }) export class PostsModule {} |
Now, in our PostsService, we can inject the Posts repository.
1 |
import { InjectRepository } from '@nestjs/typeorm'; |
1 2 3 4 |
constructor( @InjectRepository(Post) private postsRepository: Repository<PostEntity> ) {} |
Finding
With the find function, we can get multiple elements. If we don’t provide ith with any options, it returns all.
1 2 3 |
getAllPosts() { return this.postsRepository.find(); } |
To get just one element we use the findOne function. By providing it with a number we indicate that we want an element with a particular id. If the result is undefined, it means that the element wasn’t found.
1 2 3 4 5 6 7 |
async getPostById(id: number) { const post = await this.postsRepository.findOne(id); if (post) { return post; } throw new HttpException('Post not found', HttpStatus.NOT_FOUND); } |
Creating
By using the create function, we can instantiate a new Post. We can use the save function afterward to populate the database with our new entity.
1 2 3 4 5 |
async createPost(post: CreatePostDto) { const newPost = await this.postsRepository.create(post); await this.postsRepository.save(newPost); return newPost; } |
Modifying
To modify an existing element, we can use the update function. Afterward, we would use the findOne function to return the modified element.
1 2 3 4 5 6 7 8 |
async updatePost(id: number, post: UpdatePostDto) { await this.postsRepository.update(id, post); const updatedPost = await this.postsRepository.findOne(id); if (updatedPost) { return updatedPost } throw new HttpException('Post not found', HttpStatus.NOT_FOUND); } |
A significant thing is that it accepts a partial entity, so it acts as a PATCH, not as a PUT. If you want to read more on PUT vs PATCH (although with MongoDB), check out TypeScript Express tutorial #15. Using PUT vs PATCH in MongoDB with Mongoose
Deleting
To delete an element with a given id, we can use the delete function.
1 2 3 4 5 6 |
async deletePost(id: number) { const deleteResponse = await this.postsRepository.delete(id); if (!deleteResponse.affected) { throw new HttpException('Post not found', HttpStatus.NOT_FOUND); } } |
By checking out the documentation of the DELETE command, we can see that we have access to the count of removed elements. This data is available in the affected property. If it equals zero, we can assume that the element does not exist.
Handling asynchronous errors
A beneficial thing about NestJS controllers is that they handle asynchronous errors very well.
1 2 3 4 |
@Get(':id') getPostById(@Param('id') id: string) { return this.postsService.getPostById(Number(id)); } |
If the getPostById function throws an error, NestJS catches it automatically and parses it. When using pure Express, we would do this ourselves:
1 2 3 4 5 6 7 8 9 |
getAllPosts = async (request: Request, response: Response, next: Next) => { const id = request.params.id; try { const post = await this.postsService.getPostById(); response.send(post); } catch (error) { next(error); } } |
Summary
In this article, we’ve gone through the basics of connecting our NestJS application with a PostgreSQL database. Not only did we use TypeORM, but we’ve also looked into some SQL queries. NestJS and TypeORM have lots of features built-in and ready to use. In the upcoming parts of this series, we will look into them more, so stay tuned!
I like the series but posts tend to be really chaotic and missing some steps/vital information. Like here – where does docker start pgadmin ?Or you define the post entity, and then check the table structure in pgadmin, but we’ve never actually run anything yet. And you can’t run the server at this step, since the rest of the app was not updated (
post.service
for instance).I’m glad you like the series. Thanks for the feedback.
Pgadmin is defined in the docker-compose.yml file shared at the top of the article.
Is it have inbuilt retry functionality to connect with the database in case of any error? if it has, may I know how it is working b/w node_modules @nestjs/typeorm, typeorm, pg?
Thanks for this great article. It helps much.
I have two questions.
1. There is any way that automates the creation of the DB?
It seems that we should write our query manually, and I think it’s not much interested that do the exact same thing when we want to deploy it on real servers or event Netlify.
2. How to have only one .env file in dockerized projects?
I’m working on a dockerized project that some variables are shared between them. I don’t want to have separated .env files for each project.
Thanks and best of luck.
2: There are env_file option for docker-compose. You can specify the same .env file for each service.
Thanks.
What exactly do you mean by creation of the database?
Actually, it was a misunderstanding from me (:
Sorry for that.
Can you explain what is your misunderstanding? I think I have the same problem of comprehension than yours and it results with an ERROR [TypeOrmModule] Unable to connect to the database. Retrying (3)…
error: database “admin” does not exist.
Thank Wanago so much for this awesome series. I really love them and they help me a lot.
I have a question about your docker-compose please?
I see you have create services for “postgres”, “pgadmin”, that’s really good. But I don’t see that you create a service for “Nest server API”.
So if you run server normally with “yarn start:dev” for example, how is your server connect with docker container postgres ?
In my case, I need to create other service for server API in docker-compose (and run with Dockerfile). And I run them together with docker-compose up/build.
Thanks so much for your time.
I wanted to ask, how you linked the postgres with web server in docker. and you how you given the docker env for postgres connection in images filesystem?
ports:
– “5432:5432”
Means that the database will be able to handle connections from host machine (localhost:5432), so yes, node app on host machine will be able to connect to dockerized database. If you want to run the whole app in containers, just make sure you use the same network in docker-compose, and use container name as hostname for database (postgres:5432)
More info about docker networking available in docker documentation.
i am using ubuntu, after running docker compose, how do i use PG admin ? where can i use PG Admin like local ?
pgAdmin is available at http://localhost:8080/ if you are running docker-compose properly with the configuration mentioned in this article.
Hi Marcin, what’s the credentials for the pgAdmin that is running on http://localhost:8080/ ? I tried using my local machine pgAdmin password and credentials from .env file of this project, but it throwing invalid credentials?
find this amazing blog in google. nice content, thank you!
Hello, cant run service and have a Error on this steps
” [ExceptionHandler] Nest can’t resolve dependencies of the PostsService (?). Please make sure that the argument PostRepository at index [0] is available in the AppModule context.”
it’s normally?
I expect this is no longer an issue for you being a year old comment but for the sake of others with similar issue:
Remember to add PostsService to the ‘exports’ array of your PostsModule. i.e.
Great series, just started applying the tutorials to a demo course, thanks Marcin! I only had a couple of issues in my local env. Had to change the following lines or I would get errors
database.module.ts
posts.service.ts constructor
How you change that?
Hey Alex, in the tutorial above there are the original lines that were posted. I commented with the changes I made.
You save my! Thanks a lot <3
Starting from this point – couldn’t find out where, when and how did the TypeORM worked for us. I mean – i suppose that it’s assumed that at that moment there should be a tables created but i can’t see none of them.
Have i missed something? Or the author meant that some actions should be taken by a reader himself?
Thanks.
TypeORM should create appropriate tables when you run the application assuming you have the synchronize flag turned on.
Hi Wanago, When I login to pgAdmin, and expand the Service icon on the treeview to the left of the pgAdmin user interface, there is nothing there. Is there anything I have missed?
@Fengwei did you manage to figure out what was wrong? I have the same issue…
Maybe I’m late to the party, but pretty sure that it will be helpful for other guys. So the issue is that you run pgadmin, but you should also create connection to server. I resolved this issue by adding this lines to docker-compose file,
networks:
– postgres
environment:
– POSTGRES_HOST_AUTH_METHOD=trust
hostname: postgres,
docker-compose up , then go to localhost:8080, and you need to create the connection by clicking to register server, give the name of the server(whatever you want, for example nestjs), after that go to the connection tab, fill hostname/address with the hostname you provided to docker-compose file(postgres in our case),
so the form should look like this,
hostname/address: postgres
port:5432
maintenance database: postgres
username: admin,
password: admin,
role: ”,
service:”.
Click save, and you should see that connection is established and on left panel should appear server called nestjs
You will need to login to the PostgreSQL database using pgAdmin. TypeOrm will automatically create the tables if the synchornize option is set to true. I host my PostgreSQL on AWS RDS and I can view and query anything using pgAdmin. It is a great tool. It is not possible with Nest to view the raw tables. You may use querybuilder to get the raw entities but I have never used them.
Thanks for this great article. Got one question.
When I run npm ran start:dev, it typeorm would create table based on the entities, right?
I connected the pgadmin and didn’t see anything. Is it right?
I figured out there is a stupid mistake I made. Now, everything works. Thanks
hey Justin, I have the same issue. How did you resolve that please?
when connecting pgadmin, use the address “postgres” instead of “localhost”
I set my HOST envvar to ‘host.docker.internal’ in order for TypeORM to successfully connect. Couldn’t get a connection through ‘localhost’ or ‘postgres’
Hi Marcin,
thanks a lot for this tutorial.
I have some problem when I run npm run start because I receive this error:
—————————————————————————————————
—————————————————————————————————
I can say you that I’m able to connect to postgresql via CLI; here some log:
—————————————————————————————————
—————————————————————————————————
I have tryed also you branch part-2 but I receive the same error.
How can I fix it?
thanks in advance
You can fix it by allowing access to the database. You may have restricted it by using private domain wherever you are hosting your database. This happened to me as well when I used AWS RDS. I had to change the policies for allowing accessing to the databse with a public URL
Hi Marcin,
I discovered the problem: I had a previous local installation of Postgresql, so when typeOrm tryed to connect to Dockerzied Postgresql I had the error.
I uninstalled Postgresql on my local machine and all work.
Maybe at the beginning of this lesson, you could give an hint to remove any previous installation of Postgresql.
You can ignore my previous message.
Thank you.
Thanks a lot for this article? Do you have any experience with Sequelize ORM? I have some and It seems very inconvenient to use because of lack of query-builder and Typescript (written on Javascript, extra package required). Looking forward to use TypeORM. If you have Sequelize experience, could you please compare Sequelize and TypeORM?
Thanks for this article, but I am yet to see how one2one relationships are handled here.
Hi
How can we automatically generate and run migrations when application starts with the database module?
I try to do so but it didn’t work out (
I’m really enjoying it is a different approach than just following a video and playing it. Congratulations and I dare to suggest the creation of a course perhaps in this same footprint and perhaps with some deliberate mistakes to break your head a little. After all, that’s what we’re going to find on the market.
Why should we use synchronize: true flag for DatabaseModule? How can we use migrations?
If set to false. You will not be able to create new columns in the entities. This is done to restrict users from modifying the entities when in production environment.
First of all, I’d like to say big Thank You to Marcin for producing such a cool tutorial!
Now I’ll share a few issues that I encountered with this particular post.
1) There is an issue with docker-compose config and macOS (Catalina or newer). It turns out that root path (“/”) is not writable so docker-compose is not able to mount “/data/postgres” or “/data/pgadmin” as a volume. So I replaced them with “/var/tmp/docker/<whatever-name>” and it worked fine. It looks like this:
2) Regarding the connection to database via pgAdmin, this comment was helpful.
3) There are typos in code examples. Please refer to this comment.
4) When you initially run your app and connect to database (via pgAdmin or somehow else), there is not going to be any “post” table. It will be created lazily when you push first data to it.
Finally if someone lacks instructions regarding database and pgAdmin setup, the workflow is as follows. First, run “docker-compose up” in the project directory and wait till everything is started. Then, build the app and run it. Now you should be good:)
I’m getting this problem
invalid length of startup packet.
what could be the solution
I really wished to follow your tutorials, since you cover a lot, but they are too messy.
You probably didn’t try to follow your own tutorial and see if stuff works / does it make any sense.
I’m wasting a lot of time on error fixing / looking up missing information and trying to make stuff work, and for now I’m just going to abandon it and find other tutorials that work and properly guide through this stuff.
Thanks for the effort, I’m sure you tried to put your heart into this – I hope to come back at another time and find it better.
Hi. If you have any issues, feel free to join our Discord and ask.
Have a good day 🙂
http://wanago.io/discord
Thanks, appreciated. I just joined
I am going to be creating a same tutorial just like Marcin’s. My tutorial will be focused on creating an email marketing application using the same technologies. I will try to improve as much as I can. When finished, I will post a comment here. You may give me a feedback?
good, but your example code makes me hard to understand. I need to visit your GitHub repository to understand it.
PostEntity is Post, you need to define the name more clear for class at post.entity.ts
So what’s Post in InjectRepository(Post) ?
Thanks for this great article. I have an issue about synchronize to database, cause the config typeorm ‘synchronize: true’ but the database not created after run the code with no error. I had try change to this code but still not synchronize
entities: [
__dirname + ‘/../**/*.entity{.ts,.js}’,
],
const updatedPost = await this.postsRepository.findOne(id);
findOne(id)
no longer works like this the syntax probably updated or somthing else
now it is working like
findOne({
where: { id },
});
thanks me later <3
That’s true. I wrote a separate article about it:
API with NestJS #67. Migrating to TypeORM 0.3
Cheers!
Hello, everyone can help me this error
throw new Error(
Config validation error: ${error.message}
);Error: Config validation error: “POSTGRES_HOST” is required.
Thank you very much!
Hi. Did you create the .env file with the POSTGRES_HOST variable?
This is my .env file:
Great
The tutorial was awesome and I learned a lot