Welcome to your first lesson in building the Reading Tracker API with NestJS! In this lesson, you will learn how to let users add new resources — specifically, new books — to your API. In the world of web APIs, a "resource" is just a piece of data, like a book, a user, or a review. When you want to add a new resource, you usually use a POST request. As a reminder, POST request is part of the HTTP protocol and is typically used when the client wants to send data to the server to create a new resource. In our case, the resource is a book.
For example, if you want to let someone add a new book to your reading tracker, you would create a POST endpoint. This endpoint will accept information about the book (like its title and author) and store it in your system. This is a common pattern in almost every web application.
By the end of this lesson, you will know how to:
- Define a DTO (Data Transfer Object) to validate input.
- Create a POST endpoint in a controller.
- Use the UUID library to generate unique IDs for new resources.
Every resource in your system (book, user, session) needs a unique identifier. Instead of using simple numbers like 1, 2, 3, we use UUIDs (Universally Unique Identifiers).
A UUID is a long, random-looking string such as:
550e8400-e29b-41d4-a716-446655440000
They are designed to be globally unique, so you can safely generate IDs without worrying about collisions. UUIDs are commonly used in APIs, databases, and distributed systems.
In Node.js, we use the uuid library. Normally, you install it with:
But in the CodeSignal environment, everything is already pre-installed — so you’re ready to use it right away.
Every time we create a new user or book, uuidv4() generates a fresh, unique id.
When someone sends data to your API (for example, to add a new book), you want to make sure the data is correct. This is where a Data Transfer Object (DTO) comes in. A DTO is a simple class that describes what data you expect and helps validate it.
DTO stands for Data Transfer Object. It acts as a contract between the client (like a frontend or mobile app) and your API. When someone wants to send data to your server (like creating a book), they must follow the structure you define in the DTO.
DTOs ensure:
- Your code knows exactly what shape of data to expect.
- Invalid or missing data is caught early before it breaks your business logic.
- The frontend and backend can evolve independently while maintaining agreed structure.
To use these validation decorators, you need to install the validation libraries:
These libraries integrate with NestJS and automatically check incoming data before it reaches your service. If a request doesn’t pass validation (e.g., title is missing), NestJS returns a clear 400 Bad Request response — no manual checks required.
Here’s an example DTO for creating a new book:
Explanation:
@IsString()and@IsNotEmpty()are decorators from theclass-validatorlibrary. They make sure that bothtitleandauthorare non-empty strings.
Now, let’s see how to actually create a POST endpoint that uses this DTO. In NestJS, you use a controller to define your endpoints.
Here’s how you set up the POST endpoint for adding a new book:
Explanation:
@Controller('books')means all routes in this controller will start with/books.@Post()creates aPOSTendpoint at/books.@Body() createBookDto: CreateBookDtotells NestJS to take the request body, validate it using theCreateBookDto, and pass it to thecreatemethod.- The controller then calls the service to actually add the book.
NestJS automatically:
- Transforms the incoming JSON payload into an instance of the CreateBookDto class.
The controller passes the validated data to a service, which handles the logic of adding the new book to your database (in this case, an in-memory array).The service actually creates the new book and assigns it a UUID.
Here’s the service code:
Explanation:
- The service gets the current list of books from the
DatabaseService. - It creates a new book object, giving it a unique
id. - The new book is added to the list and returned.
Example Request:
Example response:
This is what the client will see after successfully adding a book.
In production applications:
- You might receive data from untrusted sources — frontend apps, third-party integrations, or mobile apps. You can't rely on them to always send clean data.
- Validating user input at the boundary (controller level) protects your system from:
- Missing required fields
- Malformed types (e.g.,
title: 123) - Security vulnerabilities (e.g., injection attacks)
- DTOs create a shared contract between frontend and backend teams. If someone changes the API structure, they can quickly detect and fix mismatches.
- UUIDs guarantee uniqueness across all resources, making your API safe and predictable.
Without DTOs and validation: "Garbage in, garbage out" — your services and database may break or store bad data.
In this lesson, you learned how to:
- Use UUIDs to generate unique IDs for books.
- Use a
DTOto validate incoming data for a new resource. - Create a
POSTendpoint in a NestJS controller. - Pass validated data to a service to add a new book.
These are the core steps for letting users add new resources to your API. And remember: a clean, validated API is easier to maintain, safer to expose to users, and more pleasant to work with as your project grows. Whether you're building a solo app or collaborating with a frontend team — DTOs, validation, and service delegation will save you hours of debugging.
In the practice exercises that follow, you’ll get hands-on experience creating and testing your own POST endpoints with DTOs. This will help you build confidence in handling user input and structuring your API for real-world use.
