Welcome to this lesson on creating a ToDo item provided from the request body using NestJS. So far, you have learned how to handle GET
requests to fetch all ToDo items and fetch a single ToDo item by its ID. In this lesson, we'll expand on that by focusing on how to create a new ToDo item using a POST
request. We will dive into the details of the controller and service layers, as well as using Data Transfer Objects (DTOs).
A POST
request is a type of HTTP request method used within the context of RESTful APIs to send data to a server to create a new resource. In REST architecture, POST
requests are utilized to submit data enclosed in the request body (as opposed to data in the URL) to a specified endpoint, which processes the data and creates a new resource. This method is typically used to create new entries in a database, such as adding a new Todo item to a Todo list. The server then processes this information and often responds with a representation of the newly created resource, including any additional data the server has added, like a unique identifier.
Unlike GET
requests, which retrieve data, POST
requests send data within the request body to a server endpoint, where it is processed and used to create a new resource, such as adding a new Todo item to a list. While a GET
request might fetch the current list of Todo items or details of a specific item, a POST
request is used to submit new information, like a new task, which the server stores in the database. We often like to talk in the terms of mutating (changing) data. In a REST API, it is typical for GET
requests to query data but not mutate it. POST
requests (and similar PUT
and DELETE
requests which we'll learn about in the next lesson) mutate the data. Because of this, you'll often hear people refer to queries
and mutations
in an API.
The controller in our NestJS application handles incoming HTTP requests and sends responses. In this case, the TodoController
will manage our POST
requests for creating new ToDo items.
Here’s a detailed breakdown of the provided TodoController
code snippet:
TypeScript1@Controller('todos') 2export class TodoController { 3 constructor(private readonly todoService: TodoService) {} 4 5 // ... Existing GET handlers 6 7 @Post() // Decorate the create method to declare that this handles POST requests 8 create( 9 // Decorate this data object with @Body() to declare that the data comes 10 // from the HTTP body and not the URL 11 @Body() todo: CreateTodoDto, 12 ): TodoDto { 13 return this.todoService.createTodo(todo); 14 } 15}
This controller sets up our route to handle the creation of ToDo items.
The TodoService
handles our business logic – in this case, creating new ToDo items. Let’s delve into the provided TodoService
code snippet:
TypeScript1@Injectable() 2export class TodoService { 3 private todos: TodoDto[] = []; 4 5 // ... Existing fetch methods 6 7 createTodo(todo: CreateTodoDto): TodoDto { 8 // The CreateTodoDto is a subset of the TodoDto. It only includes the title 9 // and description so we need to populate the id and the completed fields. 10 const newTodo = { 11 id: Date.now().toString(), 12 ...todo, 13 completed: false, 14 }; 15 16 // Add the new Todo to the collection 17 this.todos.push(newTodo); 18 19 // Return the new Todo that we created. 20 return newTodo; 21 } 22}
The service layer encapsulates our application's business logic and keeps the controller layer lean.
DTOs are used to define the structure of data being transferred and perform validation. Here, we use two DTOs:
The TodoDto
defines the structure of a Todo item when retrieving data, specifically for GET
requests. It ensures that whenever a ToDo item is fetched, it has the required properties like id
, title
, description
, and completed
. By defining these fields explicitly, we ensure consistency in the data format across different parts of the application.
TypeScript1export class TodoDto { 2 readonly id: string; 3 readonly title: string; 4 readonly description: string; 5 readonly completed: boolean; 6}
DTOs help ensure that the data follows a predefined structure, making the application more robust and secure.
The CreateTodoDto
is used when creating a new Todo item, particularly for POST
requests. Unlike TodoDto
, this class is a subset of the data, containing only the properties that are relevant when creating a new Todo: the title
and description
. This design prevents users from sending unnecessary or potentially dangerous fields like id
or completed
, which are instead managed in the TodoService
.
TypeScript1export class CreateTodoDto { 2 readonly title: string; 3 readonly description: string; 4}
In this lesson, we covered how to create a new ToDo item from a request body using NestJS. We explored the roles of the controller and service layers, the importance of DTOs in defining data structures, and walked through a practical example of creating a ToDo item using a POST
request.
Here’s a quick recap:
- The
TodoController
handles thePOST
request and calls the service method. - The
TodoService
contains the business logic to create and store the new ToDo item. - DTOs ensure the integrity and structure of the data being transferred.
Up next, you’ll have the opportunity to practice these concepts through hands-on exercises. This practice will help solidify your understanding and give you the confidence to build and expand a ToDo REST API using NestJS.