From c58b1b05148d3245f42787278a7f43767aa4e65c Mon Sep 17 00:00:00 2001 From: Diana Lau Date: Sat, 13 Oct 2018 16:34:57 -0400 Subject: [PATCH] docs: clean up todo tutorial --- docs/site/todo-tutorial-controller.md | 145 +++--------------- docs/site/todo-tutorial-model.md | 23 ++- .../site/todo-tutorial-putting-it-together.md | 45 +----- docs/site/todo-tutorial-repository.md | 78 +++------- examples/todo/README.md | 3 +- 5 files changed, 54 insertions(+), 240 deletions(-) diff --git a/docs/site/todo-tutorial-controller.md b/docs/site/todo-tutorial-controller.md index 97e3e3438d48..0aa16f797208 100644 --- a/docs/site/todo-tutorial-controller.md +++ b/docs/site/todo-tutorial-controller.md @@ -26,147 +26,42 @@ For more information about Controllers, see ### Create your controller -So, let's create a controller to handle our Todo routes. You can create an empty -Controller using the CLI as follows: +You can create a REST controller using the CLI as follows: ```sh lb4 controller ? Controller class name: todo -? What kind of controller would you like to generate? Empty Controller +? 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? Todo +? 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? /todos + create src/controllers/todo.controller.ts + update src/controllers/index.ts + +Controller todo was created in src/controllers/ ``` -In addition to creating the handler functions themselves, we'll also be adding -decorators that setup the routing as well as the expected parameters of incoming -requests. - -First, we need to define our basic controller class as well as plug in our -repository, which we'll use to perform our operations against the datasource. - -#### src/controllers/todo.controller.ts - -```ts -import {repository} from '@loopback/repository'; -import {TodoRepository} from '../repositories/todo.repository'; - -export class TodoController { - constructor(@repository(TodoRepository) protected todoRepo: TodoRepository) {} -} -``` - -The `@repository` decorator will retrieve and inject an instance of the -`TodoRepository` whenever an inbound request is being handled. The lifecycle of -controller objects is per-request, which means that a new controller instance is -created for each request. As a result, we want to inject our `TodoRepository` -since the creation of these instances is more complex and expensive than making -new controller instances. +Let's review the `TodoController` located in +`src/controllers/todo.controller.ts`. The `@repository` decorator will retrieve +and inject an instance of the `TodoRepository` whenever an inbound request is +being handled. The lifecycle of controller objects is per-request, which means +that a new controller instance is created for each request. As a result, we want +to inject our `TodoRepository` since the creation of these instances is more +complex and expensive than making new controller instances. > **NOTE**: You can customize the lifecycle of _all_ bindings in LoopBack 4! > Controllers can easily be made to use singleton lifecycles to minimize startup > costs. For more information, see the > [Dependency injection](Dependency-injection.md) section of our docs. -Now that the repository is connected, let's create our first controller -function. - -#### src/controllers/todo.controller.ts - -```ts -import {repository} from '@loopback/repository'; -import {TodoRepository} from '../repositories'; -import {Todo} from '../models'; -import {HttpErrors, post, param, requestBody} from '@loopback/rest'; - -export class TodoController { - constructor(@repository(TodoRepository) protected todoRepo: TodoRepository) {} - - @post('/todos') - async createTodo(@requestBody() todo: Todo) { - if (!todo.title) { - throw new HttpErrors.BadRequest('title is required'); - } - return await this.todoRepo.create(todo); - } -} -``` - -In this example, we're using two new decorators to provide LoopBack with -metadata about the route, verb and the format of the incoming request body: +In this example, there are two new decorators to provide LoopBack with metadata +about the route, verb and the format of the incoming request body: - `@post('/todos')` creates metadata for `@loopback/rest` so that it can redirect requests to this function when the path and verb match. - `@requestBody()` associates the OpenAPI schema for a Todo with the body of the - request so that LoopBack can validate the format of an incoming request - (**Note**: As of this writing, schematic validation is not yet functional). - -We've also added our own validation logic to ensure that a user will receive an -error if they fail to provide a `title` property with their `POST` request. - -Lastly, we are using the functions provided by our `TodoRepository` instance to -perform a create operation against the datasource. - -You can use these and other decorators to create a REST API for a full set of -verbs: - -#### src/controllers/todo.controller.ts - -```ts -import {repository} from '@loopback/repository'; -import {TodoRepository} from '../repositories'; -import {Todo} from '../models'; -import { - HttpErrors, - post, - param, - requestBody, - get, - put, - patch, - del, -} from '@loopback/rest'; - -export class TodoController { - constructor(@repository(TodoRepository) protected todoRepo: TodoRepository) {} - - @post('/todos') - async createTodo(@requestBody() todo: Todo) { - if (!todo.title) { - throw new HttpErrors.BadRequest('title is required'); - } - return await this.todoRepo.create(todo); - } - - @get('/todos/{id}') - async findTodoById(@param.path.number('id') id: number): Promise { - return await this.todoRepo.findById(id); - } - - @get('/todos') - async findTodos(): Promise { - return await this.todoRepo.find(); - } - - @put('/todos/{id}') - async replaceTodo( - @param.path.number('id') id: number, - @requestBody() todo: Todo, - ): Promise { - return await this.todoRepo.replaceById(id, todo); - } - - @patch('/todos/{id}') - async updateTodo( - @param.path.number('id') id: number, - @requestBody() todo: Todo, - ): Promise { - await this.todoRepo.updateById(id, todo); - } - - @del('/todos/{id}') - async deleteTodo(@param.path.number('id') id: number): Promise { - await this.todoRepo.deleteById(id); - } -} -``` + request so that LoopBack can validate the format of an incoming request. Some additional things to note about this example: diff --git a/docs/site/todo-tutorial-model.md b/docs/site/todo-tutorial-model.md index e624f596e7dc..e8c661c22c0a 100644 --- a/docs/site/todo-tutorial-model.md +++ b/docs/site/todo-tutorial-model.md @@ -36,13 +36,12 @@ let you label tasks so that you can distinguish between them, add extra information to describe those tasks, and finally, provide a way of tracking whether or not they're complete. -For our Todo model to represent our Todo instances for our business domain, it -will need: +The to-do model has the following properties: -- a unique id -- a title -- a description that details what the todo is all about -- a boolean flag for whether or not we've completed the task +- `id`: a unique id +- `title`: a title +- `desc`: a description that details the specific task to be accomplished +- `isComplete`: a boolean flag for whether or not we’ve completed the task We can use the `lb4 model` command and answer the prompts to generate the model for us. Press `return` with an empty property name to generate the model. Follow @@ -51,15 +50,15 @@ these steps: ```sh lb4 model ? Model class name: todo -? Please select the model base class Entity +? Please select the model base class: Entity Let's add a property to Todo Enter an empty property name when done ? Enter the property name: id ? Property type: number -? Is ID field? Yes -? Required?: No +? Is id the ID property? Yes +? Is it required?: No ? Default value [leave blank for none]: Let's add another property to Todo @@ -67,7 +66,7 @@ Enter an empty property name when done ? Enter the property name: title ? Property type: string -? Required?: Yes +? Is it required?: Yes ? Default value [leave blank for none]: Let's add another property to Todo @@ -75,7 +74,7 @@ Enter an empty property name when done ? Enter the property name: desc ? Property type: string -? Required?: No +? Is it required?: No ? Default value [leave blank for none]: Let's add another property to Todo @@ -83,7 +82,7 @@ Enter an empty property name when done ? Enter the property name: isComplete ? Property type: boolean -? Required?: No +? Is it required?: No ? Default value [leave blank for none]: Let's add another property to Todo diff --git a/docs/site/todo-tutorial-putting-it-together.md b/docs/site/todo-tutorial-putting-it-together.md index 0a24f89c2be9..2e8a07ccd138 100644 --- a/docs/site/todo-tutorial-putting-it-together.md +++ b/docs/site/todo-tutorial-putting-it-together.md @@ -9,7 +9,7 @@ summary: LoopBack 4 Todo Application Tutorial - Putting it all together ### Putting it all together -We've got all of our artifacts now, and all that's left is to bind them to our +We've got all of our artifacts now, and they are all automatically bound to our [Application](Application.md) so that LoopBack's [Dependency injection](Dependency-injection.md) system can tie it all together for us! @@ -31,49 +31,6 @@ artifacts and inject them into our application for use. > [Booters](Booting-an-Application.md#booters) section of > [Booting an Application](Booting-an-Application.md). -#### src/application.ts - -```ts -import {BootMixin} from '@loopback/boot'; -import {ApplicationConfig} from '@loopback/core'; -import {RepositoryMixin} from '@loopback/repository'; -import {RestApplication, RestServer} from '@loopback/rest'; -import {MySequence} from './sequence'; - -export class TodoListApplication extends BootMixin( - RepositoryMixin(RestApplication), -) { - constructor(options?: ApplicationConfig) { - super(options); - - // Set up the custom sequence - this.sequence(MySequence); - - this.projectRoot = __dirname; - // Customize @loopback/boot Booter Conventions here - this.bootOptions = { - controllers: { - // Customize ControllerBooter Conventions here - dirs: ['controllers'], - extensions: ['.controller.js'], - nested: true, - }, - }; - } - - async start() { - await super.start(); - - const server = await this.getServer(RestServer); - const port = await server.get('rest.port'); - console.log(`Server is running at http://127.0.0.1:${port}`); - console.log(`Try http://127.0.0.1:${port}/ping`); - } -} -``` - -### Try it out - Let's try out our application! First, you'll want to start the app. ```sh diff --git a/docs/site/todo-tutorial-repository.md b/docs/site/todo-tutorial-repository.md index 263b112f5af5..a04b7caefaa6 100644 --- a/docs/site/todo-tutorial-repository.md +++ b/docs/site/todo-tutorial-repository.md @@ -24,67 +24,29 @@ For more information about Repositories, see ### Create your repository -In the `src/repositories` directory, create two files: - -- `index.ts` (our export helper) -- `todo.repository.ts` - -> **NOTE:** The `index.ts` file is an export helper file; this pattern is a huge -> time-saver as the number of models in your project grows, because it allows -> you to point to the _directory_ when attempting to import types from a file -> within the target folder. **We will use this concept throughout the tutorial! -> For more info, see TypeScript's -> [Module Resolution](https://www.typescriptlang.org/docs/handbook/module-resolution.html) -> docs.** - -```ts -// in src/models/index.ts -export * from './foo.model'; -export * from './bar.model'; -export * from './baz.model'; - -// elsewhere... - -// with index.ts -import {Foo, Bar, Baz} from './models'; -// ...and without index.ts -import {Foo} from './models/foo.model'; -import {Bar} from './models/bar.model'; -import {Baz} from './models/baz.model'; -// Using an index.ts in your artifact folders really helps keep -// things tidy and succinct! +From inside the project folder, run the `lb4 repository` command to create a +repository for your to-do model using the `db` datasource from the previous +step. The `db` datasource shows up by its class name `DbDataSource` from the +list of available datasources. + +```sh +lb4 repository +? Please select the datasource DbDatasource +? Select the model(s) you want to generate a repository Todo + create src/repositories/todo.repository.ts + update src/repositories/index.ts + +Repository Todo was created in src/repositories/ ``` -Our TodoRepository will extend a small base class that uses the -`DefaultCrudRepository` class from -[`@loopback/repository`](https://github.com/strongloop/loopback-next/tree/master/packages/repository) -and will define the model type we're working with, as well as its ID type. This -automatically gives us the basic CRUD methods required for performing operations -against our database (or any other kind of datasource). - -We'll also inject our datasource so that this repository can connect to it when -executing data operations. - -#### src/repositories/todo.repository.ts - -```ts -import {DefaultCrudRepository, juggler} from '@loopback/repository'; -import {Todo} from '../models'; -import {inject} from '@loopback/core'; - -export class TodoRepository extends DefaultCrudRepository< - Todo, - typeof Todo.prototype.id -> { - constructor(@inject('datasources.db') dataSource: juggler.DataSource) { - super(Todo, dataSource); - } -} -``` +The `src/repositories/index.ts` file makes exporting artifacts central and also +easier to import. -Now we have everything we need to perform CRUD operations for our Todo list, -we'll need to build the [Controller](todo-tutorial-controller.md) to handle our -incoming requests. +The newly created `todo.repository.ts` class has the necessary connections that +are needed to perform CRUD operations for our to-do model. It leverages the Todo +model definition and 'db' datasource configuration and retrieves the datasource +using +[Dependency Injection](https://loopback.io/doc/en/lb4/Dependency-injection.html). ### Navigation diff --git a/examples/todo/README.md b/examples/todo/README.md index 1d9541ff479a..b759575b87a4 100644 --- a/examples/todo/README.md +++ b/examples/todo/README.md @@ -5,7 +5,8 @@ This is the basic tutorial for getting started with Loopback 4! ## Overview This tutorial demonstrates how to create a basic API for a todo list using -LoopBack 4. +LoopBack 4. You will experience how you can create REST APIs with just +[5 steps](#steps). ![todo-tutorial-overview](https://loopback.io/pages/en/lb4/imgs/todo-overview.png)