Becoming More Proficient on the Back-End (Part 2)

Joe Previte
Joe PreviteThursday, August 15, 2019
A calendar on a table with a coffee mug on top.

In case you missed it, check out Part 1 where I talk about my Q3 goals and explain how this series works.

Now, here’s Part 2!

Progress Update

During the week of July 21st, my goal was to complete the following:

  • Modern TS Course
  • Validation and Error Handling — 30 mins
  • Data Persistence — PostgresSQL & TypeORM — 1 hour

Completed Goal

I put in extra hours this weekend to get back on track for my plan so I completed both of the course sections.

🤔 What did I do?

I learned about validation, error handling and data persistence. I also integrated TypeORM and a PostgresSQL database.

💡 Key Learnings

Again, I have experience in these areas but here are some things that stuck out this time around:

  • data transfer objects (DTOs)

A data transfer object is essentially the definition of a piece of data, which may be used across multiple layers of your application.

For instance, in the Nest.js application I’m building, there is a /tasks controller. On the controller, we have a POST endpoint on the root where you can create a task. The controller utilizes the service (where the logic actually lives). Since these both accept the same parameter when creating a task, this is perfect use case for a DTO. We create a create-task.dto.ts which looks like this:

export class CreateTaskDto { title: string; description: string; }

Then, import it wherever we need it within the application. Viola!

One comment the instructor made was to define it using ES6 Classes instead of a TypeScript interface, so the shape would be preserved after the TS complication to JS. This also makes code easier to maintain in the future.

  • Nest.js pipes

In terms of validation, Nest.js provides classes called ValidationPipes and ParseIntPipe. I like to think of these pipes as paths we send data on. When we use this on handlers or methods within our controllers, Nest.js will "pipe the data" into these validation pipes and check them against the DTOs we provided. In this course, we use them in tandem with a package called class-validator which provides decorators for you're classes. Here's our updated create-task.dto.ts with the validators.

import { IsNotEmpty } from 'class-validator'; export class CreateTaskDto { @IsNotEmpty() title: string; @IsNotEmpty() description: string; }

As you can see we added the IsNotEmpty decorators to make sure title and description are never empty strings.

Then in our controller, we can tell Nest.js to use a Validation Pipe like so:

@Post() @UsePipes(ValidationPipe) createTask(@Body() createTaskDto: CreateTaskDto): Promise<Task> { return this.tasksService.createTask(createTaskDto); }

We’re basically saying, “Hey Nest! on this POST handler, I want you to use the ValidationPipe and validate the Body of the request again the CreateTaskDto. Sound good? Thanks!"

The ParseIntPipe is used to convert a string to a number so pipes can also be used for data transformation.

⁉️ Challenges

Below are some things that were difficult for me and that I’m still wrapping my head around.

  • repositories

After adding TypeORM and PostgresSQL, we added a “repository” layer. The documentation states:

Repository is supposed to work with your entity objects. Find entities, insert, update, delete, etc.

As outline in the docs, the next step is to create a Task entity (which essentially is a table in the database for tasks) and then create a task.repository.ts file. In this file, two methods were added: getTasks and createTask. I believe the reason behind this is because the methods involved more complex logic related to using the queryBuilder provided by TypeORM and the purpose was to separate logic.

That’s all for my update! Thanks for reading and catch ya next week! 👋

Share this post


Related Posts:

Interested in working with us?

Give us some details about your project, and our team will be in touch with how we can help.

Get in Touch