Skip to content

Commit

Permalink
feat(example-todo-list): add TodoList package/tutorial
Browse files Browse the repository at this point in the history
  • Loading branch information
shimks authored and dhmlau committed Jul 20, 2018
1 parent fa33520 commit 306d437
Show file tree
Hide file tree
Showing 49 changed files with 2,202 additions and 22 deletions.
12 changes: 8 additions & 4 deletions docs/site/Examples-and-tutorials.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ LoopBack 4 comes with the following example projects:
- **[todo](todo-tutorial.md)**: Tutorial on building a simple application with
LoopBack 4 key concepts using bottom-up approach.

- **[todo-list](todo-list-tutorial.md)**: Tutorial on introducing related models
and building their API from the Todo tutorial

- **[log-extension](https://github.com/strongloop/loopback-next/tree/master/examples/log-extension)**:
Tutorial on building a log extension.

Expand All @@ -25,11 +28,12 @@ LoopBack 4 comes with the following example projects:
You can download any of the example projects usig our CLI tool `lb4`:

```sh
lb4 example
$ lb4 example
? What example would you like to clone? (Use arrow keys)
❯ todo: Tutorial example on how to build an application with LoopBack 4.
hello-world: A simple hello-world Application using LoopBack 4
log-extension: An example extension project for LoopBack 4
> todo: Tutorial example on how to build an application with LoopBack 4.
todo-list: Continuation of the todo example using relations in LoopBack 4.
hello-world: A simple hello-world Application using LoopBack 4.
log-extension: An example extension project for LoopBack 4.
rpc-server: A basic RPC server using a made-up protocol.
```

Expand Down
17 changes: 17 additions & 0 deletions docs/site/sidebars/lb4_sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,23 @@ children:
url: todo-tutorial-geocoding-service.html
output: 'web, pdf'

- title: 'TodoList Tutorial'
url: todo-list-tutorial.html
output: 'web, pdf'
children:

- title: 'Add TodoList Model'
url: todo-list-tutorial-model.html
output: 'web, pdf'

- title: 'Add TodoList Repository'
url: todo-list-tutorial-repository.html
output: 'web, pdf'

- title: 'Add TodoList Controller'
url: todo-list-tutorial-controller.html
output: 'web, pdf'

- title: 'Key concepts'
url: Concepts.html
output: 'web, pdf'
Expand Down
169 changes: 169 additions & 0 deletions docs/site/todo-list-tutorial-controller.md
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)
115 changes: 115 additions & 0 deletions docs/site/todo-list-tutorial-model.md
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)
Loading

0 comments on commit 306d437

Please sign in to comment.