Skip to content

Commit

Permalink
docs: update todolist tutorial to include navigational properties
Browse files Browse the repository at this point in the history
  • Loading branch information
nabdelgadir committed Jun 20, 2019
1 parent df54422 commit 82a9c3d
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 4 deletions.
87 changes: 85 additions & 2 deletions docs/site/tutorials/todo-list/todo-list-tutorial-controller.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,89 @@ Controller TodoList was created in src/controllers/

And voilà! We now have a set of basic APIs for todo-lists, just like that!

#### Inclusion of Related Models

In order to get our related `Todo`s for each `TodoList`, let's update the
`schema`.

In `src/models/todo-list.controller.ts`, first import `getModelSchemaRef` from
`@loopback/rest`.

Then update the following `schema`s in `responses`'s `content`:

{% include code-caption.html content="src/models/todo-list.controller.ts" %}

```ts
@get('/todo-lists', {
responses: {
'200': {
description: 'Array of TodoList model instances',
content: {
'application/json': {
schema: {
type: 'array',
items: getModelSchemaRef(TodoList, {includeRelations: true}),
},
},
},
},
},
})
async find(/*...*/) {/*...*/}

@get('/todo-lists/{id}', {
responses: {
'200': {
description: 'TodoList model instance',
content: {
'application/json': {
schema: getModelSchemaRef(TodoList, {includeRelations: true}),
},
},
},
},
})
async findById(/*...*/) {/*...*/}
```

Let's also update it in the `TodoController`:

{% include code-caption.html content="src/models/todo.controller.ts" %}

```ts
@get('/todos', {
responses: {
'200': {
description: 'Array of Todo model instances',
content: {
'application/json': {
schema: {
type: 'array',
items: getModelSchemaRef(Todo, {includeRelations: true}),
},
},
},
},
},
})
})
async findTodos(/*...*/) {/*...*/}

@get('/todos/{id}', {
responses: {
'200': {
description: 'Todo model instance',
content: {
'application/json': {
schema: getModelSchemaRef(Todo, {includeRelations: true}),
},
},
},
},
})
async findTodoById(/*...*/) {/*...*/}
```

### Create TodoList's Todo controller

For the controller handling `Todos` of a `TodoList`, we'll start with an empty
Expand Down Expand Up @@ -196,8 +279,8 @@ export class TodoListTodoController {
}
```

Check out our todo-list example to see the full source code generated for
TodoListTodo controller:
Check out our `TodoList` example to see the full source code generated for the
`TodoListTodo` controller:
[src/controllers/todo-list-todo.controller.ts](https://github.com/strongloop/loopback-next/blob/master/examples/todo-list/src/controllers/todo-list-todo.controller.ts)

### Try it out
Expand Down
6 changes: 4 additions & 2 deletions docs/site/tutorials/todo-list/todo-list-tutorial-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ Model TodoList was created in src/models/
```

Now that we have our new model, we need to define its relation with the `Todo`
model. Add the following import statements and property to the `TodoList` model:
model. Add the following import statements and property to the `TodoList` model
and update the `TodoListRelations` interface to include `todos`:

{% include code-caption.html content="src/models/todo-list.model.ts" %}

Expand Down Expand Up @@ -101,7 +102,8 @@ suggests, `@hasMany()` informs LoopBack 4 that a todo list can have many todo
items.

To complement `TodoList`'s relationship to `Todo`, we'll add in the `todoListId`
property on the `Todo` model to define the relation on both ends:
property on the `Todo` model to define the relation on both ends, along with
updating the `TodoRelations` interface to include `todoList`:

{% include code-caption.html content="src/models/todo.model.ts" %}

Expand Down
127 changes: 127 additions & 0 deletions docs/site/tutorials/todo-list/todo-list-tutorial-repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,133 @@ export class TodoListRepository extends DefaultCrudRepository<
}
```
### Inclusion of Related Models
To get the related `Todo` object for each `TodoList`, we have to override the
`find` and `findById` functions.
First add the following imports:
```ts
import {Filter, Options} from '@loopback/repository';
import {TodoListWithRelations} from '../models';
```
Add the following two functions after the constructor:
{% include code-caption.html content="src/repositories/todo-list.repository.ts" %}
```ts
async find(
filter?: Filter<TodoList>,
options?: Options,
): Promise<TodoListWithRelations[]> {
// Prevent juggler for applying "include" filter
// Juggler is not aware of LB4 relations
const include = filter && filter.include;
filter = filter && Object.assign(filter, {include: undefined});
const result = await super.find(filter, options);
// poor-mans inclusion resolver, this should be handled by DefaultCrudRepo
// and use `inq` operator to fetch related todos in fewer DB queries
if (include && include.length && include[0].relation === 'todos') {
await Promise.all(
result.map(async r => {
r.todos = await this.todos(r.id).find();
}),
);
}
return result;
}
async findById(
id: typeof TodoList.prototype.id,
filter?: Filter<TodoList>,
options?: Options,
): Promise<TodoListWithRelations> {
// Prevent juggler for applying "include" filter
// Juggler is not aware of LB4 relations
const include = filter && filter.include;
filter = filter && Object.assign(filter, {include: undefined});
const result = await super.findById(id, filter, options);
if (include && include.length && include[0].relation === 'todos') {
result.todos = await this.todos(result.id).find();
}
return result;
}
```
Now when you get a `TodoList`, a `todos` property will be included that contains
your related `Todo`s, for example:
```json
{
"id": 2,
"title": "daily routine of POTUS",
"todos": [
{
"id": 3,
"title": "terrorize senate",
"desc": "Tell them they're getting a budget cut.",
"todoListId": 2
}
]
}
```
Let's do the same on the `TodoRepository`:
{% include code-caption.html content="src/repositories/todo.repository.ts" %}
```ts
async find(
filter?: Filter<Todo>,
options?: Options,
): Promise<TodoWithRelations[]> {
// Prevent juggler for applying "include" filter
// Juggler is not aware of LB4 relations
const include = filter && filter.include;
filter = filter && Object.assign(filter, {include: undefined});
const result = await super.find(filter, options);
// poor-mans inclusion resolver, this should be handled by DefaultCrudRepo
// and use `inq` operator to fetch related todo-lists in fewer DB queries
if (include && include.length && include[0].relation === 'todoList') {
await Promise.all(
result.map(async r => {
r.todoList = await this.todoList(r.id);
}),
);
}
return result;
}
async findById(
id: typeof Todo.prototype.id,
filter?: Filter<Todo>,
options?: Options,
): Promise<TodoWithRelations> {
// Prevent juggler for applying "include" filter
// Juggler is not aware of LB4 relations
const include = filter && filter.include;
filter = filter && Object.assign(filter, {include: undefined});
const result = await super.findById(id, filter, options);
if (include && include.length && include[0].relation === 'todoList') {
result.todoList = await this.todoList(result.id);
}
return result;
}
```
We're now ready to expose `TodoList` and its related `Todo` API through the
[controller](todo-list-tutorial-controller.md).
Expand Down

0 comments on commit 82a9c3d

Please sign in to comment.