-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(example-todo-list): add TodoList package/tutorial
- Loading branch information
Showing
49 changed files
with
2,202 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
--- | ||
lang: en | ||
title: "Add TodoList and TodoList's Todo Controller" | ||
keywords: LoopBack 4.0, LoopBack 4 | ||
tags: | ||
sidebar: lb4_sidebar | ||
permalink: /doc/en/lb4/todo-list-tutorial-controller.html | ||
summary: LoopBack 4 TodoList Application Tutorial - Add TodoList and TodoList's Todo Controller | ||
--- | ||
|
||
### Controllers with related models | ||
|
||
Defining business logic to handle requests to related models isn't too different | ||
from handling requests for standalone models. We'll create controllers to handle | ||
requests for todo-lists and todo items under a todo-list. | ||
|
||
### Create TodoList controller | ||
|
||
Run the CLI command for creating a RESTful CRUD controller for our `TodoList` | ||
routes with the following inputs: | ||
|
||
```sh | ||
$ lb4 controller | ||
? Controller class name: TodoList | ||
? What kind of controller would you like to generate? REST Controller with CRUD functions | ||
? What is the name of the model to use with this CRUD repository? TodoList | ||
? What is the name of your CRUD repository? TodoRepository | ||
? What is the type of your ID? number | ||
? What is the base HTTP path name of the CRUD operations? /todo-lists | ||
create src/controllers/todo-list.controller.ts | ||
update src/controllers/index.ts | ||
|
||
Controller TodoList was created in src/controllers/ | ||
``` | ||
|
||
And voilà! We now have a set of basic APIs for todo-lists just like that! | ||
|
||
### Create TodoList's Todo controller | ||
|
||
For the controller handling `Todos` of a `TodoList`, we'll start with an empty | ||
controller: | ||
|
||
```sh | ||
$ lb4 controller | ||
? Controller class name: TodoListTodo | ||
? What kind of controller would you like to generate? Empty Controller | ||
create src/controllers/todo-list-todo.controller.ts | ||
update src/controllers/index.ts | ||
|
||
Controller TodoListTodo was created in src/controllers/ | ||
``` | ||
|
||
Let's add in an injection for our `TodoListRepository`: | ||
|
||
#### src/controllers/todo-list-todo.controller.ts | ||
|
||
```ts | ||
import {repository} from '@loopback/repository'; | ||
import {TodoListRepository} from '../repositories'; | ||
|
||
export class TodoListTodoController { | ||
constructor( | ||
@repository(TodoListRepository) protected todoListRepo: TodoListRepository, | ||
) {} | ||
} | ||
``` | ||
|
||
With this, we're now ready to add in some routes for our todo requests. To call | ||
the CRUD methods on a todo-list's todo items, we'll first need to create a | ||
constrained `TodoRepository`. We can achieve this by using our repository | ||
instance's `todos` factory function that we defined earlier in | ||
`TodoListRepository`. | ||
|
||
The `POST` request from `/todo-lists/{id}/todos` should look something like | ||
this: | ||
|
||
#### src/controllers/todo-list-todo.controller.ts | ||
|
||
```ts | ||
import {repository} from '@loopback/repository'; | ||
import {TodoListRepository} from '../repositories'; | ||
import {post, param, requestBody} from '@loopback/rest'; | ||
import {Todo} from '../models'; | ||
|
||
export class TodoListTodoController { | ||
constructor( | ||
@repository(TodoListRepository) protected todoListRepo: TodoListRepository, | ||
) {} | ||
|
||
@post('/todo-lists/{id}/todos') | ||
async create(@param.path.number('id') id: number, @requestBody() todo: Todo) { | ||
return await this.todoListRepo.todos(id).create(todo); | ||
} | ||
} | ||
``` | ||
|
||
Using our constraining factory as we did with the `POST` request, we'll define | ||
the controller methods for the rest of the HTTP verbs for the route. The | ||
completed controller should look as follows: | ||
|
||
#### src/controllers/todo-list-todo.controller.ts | ||
|
||
```ts | ||
import {repository, Filter, Where} from '@loopback/repository'; | ||
import {TodoListRepository} from '../repositories'; | ||
import {post, get, patch, del, param, requestBody} from '@loopback/rest'; | ||
import {Todo} from '../models'; | ||
|
||
export class TodoListTodoController { | ||
constructor( | ||
@repository(TodoListRepository) protected todoListRepo: TodoListRepository, | ||
) {} | ||
|
||
@post('/todo-lists/{id}/todos') | ||
async create(@param.path.number('id') id: number, @requestBody() todo: Todo) { | ||
return await this.todoListRepo.todos(id).create(todo); | ||
} | ||
|
||
@get('/todo-lists/{id}/todos') | ||
async find( | ||
@param.path.number('id') id: number, | ||
@param.query.string('filter') filter?: Filter, | ||
) { | ||
return await this.todoListRepo.todos(id).find(filter); | ||
} | ||
|
||
@patch('/todo-lists/{id}/todos') | ||
async patch( | ||
@param.path.number('id') id: number, | ||
@requestBody() todo: Partial<Todo>, | ||
@param.query.string('where') where?: Where, | ||
) { | ||
return await this.todoListRepo.todos(id).patch(todo, where); | ||
} | ||
|
||
@del('/todo-lists/{id}/todos') | ||
async delete( | ||
@param.path.number('id') id: number, | ||
@param.query.string('where') where?: Where, | ||
) { | ||
return await this.todoListRepo.todos(id).delete(where); | ||
} | ||
} | ||
``` | ||
|
||
### Try it out | ||
|
||
With the controllers complete, your application is ready to start up again! | ||
`@loopback/boot` should wire up everything for us when we start the application, | ||
so there's nothing else we need to do before we try out our new routes. | ||
|
||
```sh | ||
$ npm start | ||
Server is running at http://127.0.0.1:3000 | ||
``` | ||
|
||
Here are some new requests you can try out: | ||
|
||
- `POST /todo-lists` with a body of `{ "title": "grocery list" }`. | ||
- `POST /todo-lists/{id}/todos` using the ID you got back from the previous | ||
`POST` request and a body for a todo. Notice that response body you get back | ||
contains property `todoListId` with the ID from before. | ||
- `GET /todos/{id}/todos` and see if you get the todo you created from before. | ||
|
||
And there you have it! You now have the power to define API for related models! | ||
|
||
### Navigation | ||
|
||
Previous step: [Add TodoList repository](todo-list-tutorial-repository.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
--- | ||
lang: en | ||
title: 'Add TodoList Model' | ||
keywords: LoopBack 4.0, LoopBack 4 | ||
tags: | ||
sidebar: lb4_sidebar | ||
permalink: /doc/en/lb4/todo-list-tutorial-model.html | ||
summary: LoopBack 4 TodoList Application Tutorial - Add TodoList Model | ||
--- | ||
|
||
### Building a checklist for your Todo models | ||
|
||
A todo item is often grouped into a checklist along with other todo items so | ||
that it can be used to measure the progress of a bigger picture that the item is | ||
a part of. | ||
|
||
A set of data can often be related to another; an entity may be able to provide | ||
access to another based on its relationship with the other entity. To take | ||
`TodoListApplication` one step further and establish relations with the existing | ||
`Todo` model as real-world applications often tend to do, we'll introduce the | ||
model `TodoList`. | ||
|
||
We'll create `TodoList` model to represent a checklist that contains multiple | ||
Todo items. Let's define TodoList model with the following properties: | ||
|
||
- a unique id | ||
- a title | ||
- a color to represent the TodoList with | ||
|
||
We can use the `lb4 model` command and answer the prompts to generate the model | ||
for us as follows: | ||
|
||
```sh | ||
$ lb4 model | ||
? Model class name: TodoList | ||
|
||
Let's add a property to TodoList | ||
Enter an empty property name when done | ||
? Enter the property name: id | ||
? Property type: number | ||
? Is ID field? Yes | ||
? Required?: No | ||
? Default value [leave blank for none]: | ||
Let's add another property to TodoList | ||
Enter an empty property name when done | ||
|
||
? Enter the property name: title | ||
? Property type: string | ||
? Required?: Yes | ||
? Default value [leave blank for none]: | ||
|
||
Let's add another property to TodoList | ||
Enter an empty property name when done | ||
? Enter the property name: color | ||
? Property type: string | ||
? Required?: No | ||
? Default value [leave blank for none]: | ||
Let's add another property to TodoList | ||
Enter an empty property name when done | ||
|
||
? Enter the property name: | ||
create src/models/todo-list.model.ts | ||
update src/models/index.ts | ||
|
||
Model TodoList was created in src/models/ | ||
``` | ||
|
||
Now that we have our new model, it's time to define its relation with the `Todo` | ||
model. To `TodoList` model, add in the following property: | ||
|
||
#### src/models/todo-list.model.ts | ||
|
||
```ts | ||
@model() | ||
export class TodoList extends Entity { | ||
// ...properties defined by the CLI... | ||
|
||
@hasMany(Todo) todos?: Todo[]; | ||
|
||
// ...constructor def... | ||
} | ||
``` | ||
|
||
Notice that `@hasMany()` decorator is used to define this property. As the | ||
decorator's name suggests, this will let LoopBack 4 know that a todo list can | ||
have many todo items. | ||
|
||
To complement `TodoList`'s relationship to `Todo`, we'll add in `todoListId` | ||
property on `Todo` model to complete defining the relation on both ends: | ||
|
||
### src/models/todo.model.ts | ||
|
||
```ts | ||
@model() | ||
export class Todo extends Entity { | ||
// ...properties defined by the CLI... | ||
|
||
@property() todoListId: number; | ||
|
||
// ...constructor def... | ||
} | ||
``` | ||
|
||
Once the models have been completely configured, it's time to move on to adding | ||
a [repository](todo-list-tutorial-repository.md) for `TodoList`. | ||
|
||
### Navigation | ||
|
||
Introduction: [TodoList Tutorial](todo-list-tutorial.md) | ||
|
||
Next step: [Add TodoList repository](todo-list-tutorial-repository.md) |
Oops, something went wrong.