Skip to content

Commit

Permalink
docs(example-getting-started): tutorial cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Kevin Delisle committed Feb 26, 2018
1 parent b710c1b commit 020e9b8
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 55 deletions.
36 changes: 27 additions & 9 deletions packages/example-getting-started/docs/1-prerequisites-and-setup.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Prerequisites
## Setup

Before we can begin, you'll need to make sure you have some things installed:
- [Node.js](https://nodejs.org/en/) at v6.x or greater
Expand All @@ -9,26 +9,44 @@ certain technologies, languages and concepts.
- [npm](https://www.npmjs.com/)
- [REST](https://en.wikipedia.org/wiki/Representational_state_transfer)

## Setup
1. Install the new loopback CLI toolkit.

Lastly, you'll need to install the LoopBack 4 CLI toolkit:
```
npm i -g @loopback/cli
```
2. Download the "getting-started" application.

If you'd like to continue the tutorial, then jump to the
[next section here](2-scaffold-app.md).

If you'd like to see the final results of this tutorial as an example
application, then follow these steps:

1. Run the `lb4 example` command to clone the getting-started repository:
```
lb4 example getting-started
$ lb4 example
? What example would you like to clone? (Use arrow keys)
❯ getting-started: An application and tutorial on how to build with 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.
```

3. Switch to the directory and install dependencies.
2. Jump into the directory and then install the required dependencies:
```
cd loopback-example-getting-started && npm i
$ cd loopback4-example-getting-started && npm i
```

4. Start the app!
3. Finally, start the application!
```
npm start
$ npm start
Server is running on port 3000
```

Feel free to look around in the application's code to get a feel for how it
works, or if you're still interested in learning how to build it step-by-step,
then continue with this tutorial!

### Navigation

Next step: [Scaffolding your application](2-scaffold-app.md)
23 changes: 15 additions & 8 deletions packages/example-getting-started/docs/2-scaffold-app.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
### Create your app scaffolding

Install the `@loopback/cli` package. This will give you the command-line
toolkit that can generate a basic REST app for you.
`npm i -g @loopback/cli`
The LoopBack 4 CLI toolkit comes with templates that allow you to generate
whole applications, as well as artifacts (ex. controllers, models, repositories)
for existing applications.

Next, navigate to whichever directory you'd like to create your new project
and run `lb4`. Follow the prompts to generate your application. For this
tutorial, when prompted with the options for selecting things like whether or
not to enable certain project features (loopback's build, tslint, mocha, etc.),
leave them all enabled.
To generate your application using the toolkit, run the `lb4` command
and follow the on-screen prompts:
```
$ lb4
```

<!-- TODO: Add screenshot of terminal here to illustrate what we mean. -->

For this tutorial, when prompted with the options for selecting things like
whether or not to enable certain project features (loopback's build, tslint,
mocha, etc.), leave them all enabled.

When you're ready, we'll begin laying the groundwork for our application by
making use of the [Legacy Juggler](3-add-legacy-juggler.md).

### Navigation

Previous step: [Prerequisites and setup](1-prerequisites-and-setup.md)
Expand Down
19 changes: 19 additions & 0 deletions packages/example-getting-started/docs/3-add-legacy-juggler.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
### Adding the Legacy Juggler

The Legacy Juggler is a "bridge" between the existing
[loopback-datasource-juggler](https://github.com/strongloop/loopback-datasource-juggler)
and the new LoopBack 4 architecture. It provides the capabilities required to
access datasources, and perform
[CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations
on those datasources.

It also provides many of the functions and interfaces we'll require for setting
up our new LoopBack application, which is why we're starting here.

Jump into the directory for your new application. You'll see a folder structure
similar to this:
```
Expand Down Expand Up @@ -52,6 +62,15 @@ export class TodoApplication extends RepositoryMixin(RestApplication) {
}
}
```

Once you're ready, we'll move on to the [Add your Todo model](4-todo-model.md)
section.

For more information on the Legacy Juggler, check out the
[@loopback/repository package](https://github.com/strongloop/loopback-next/tree/master/packages/repository)
or see the [Repositories section](http://loopback.io/doc/en/lb4/Repositories.html)
of our docs.

### Navigation

Previous step: [Scaffolding your application](2-scaffold-app.md)
Expand Down
29 changes: 23 additions & 6 deletions packages/example-getting-started/docs/4-todo-model.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
### Building the Todo model

The Todo model will be the object we use both as a Data Transfer Object (DTO) on
the controller, and as a LoopBack model for the Legacy Juggler implementation.
Now we can begin working on the representation of our data for use with
LoopBack 4. To that end, we're going to create a Todo model that can represent
instances of a task for our Todo list. The Todo model will serve both as a
[Data Transfer Object](https://en.wikipedia.org/wiki/Data_transfer_object)
(also known as a DTO) for representing incoming Todo instances on requests,
as well as our data structure for use with the Legacy Juggler.

>**NOTE:** LoopBack 3 treated models as the "center" of operations; in
LoopBack 4, that is no longer the case. While LoopBack 4 provides many of the
helper methods and decorators that allow you to utilize models in a similar way,
you are no longer _required_ to do so!

Create another folder in `src` called `repositories` and inside of that folder,
create two files:
Expand All @@ -12,7 +21,8 @@ create two files:
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!
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';
Expand All @@ -29,17 +39,20 @@ import {Bar} from './models/bar.model';
import {Baz} from './models/baz.model';
```

In our Todo model, we'll create a basic representation of what would go in
a Todo list. Our model will include:
For our Todo model to represent our Todo instances, it will need:
- 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.
- a boolean flag for whether or not we've completed the task

For the Legacy Juggler to understand how to work with our model class, it
will need to extend the `Entity` type, as well as provide an override for
the `getId` function, so that it can retrieve a Todo model's ID as needed.

<!--
TODO: Remove this section once v3 is live; ideally, this won't be required
any longer!
-->
Additionally, we'll define a `SchemaObject` that represents our Todo model
as an [OpenAPI Schema Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schema-object).
This will give the OpenAPI spec builder the information it needs to describe the
Expand Down Expand Up @@ -102,6 +115,10 @@ export const TodoSchema: SchemaObject = {
required: ['title'],
};
```

Now that we have our model, it's time to add a [datasource](5-datasource.md) so
we can perform real CRUD operations!

### Navigation

Previous step: [Adding the Legacy Juggler](3-add-legacy-juggler.md)
Expand Down
9 changes: 7 additions & 2 deletions packages/example-getting-started/docs/5-datasource.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
### Building a Datasource

Before we can begin constructing controllers and repositories for our
application, we need to define our datasource.
Our Todo instances will need to have a Datasource to go with them if we're going
to create a useful application, so now we'll construct a datasource instance
that we can use in conjunction with our Todo model to perform CRUD operations
against a database.

Create a new folder in the root directory of the project called `config`,
and then inside that folder, create a `datasources.json` file. For now, we'll
Expand Down Expand Up @@ -33,6 +35,9 @@ export const db = new DataSourceConstructor(config);
This will give us a strongly-typed datasource export that we can work with to
construct our TodoRepository definition.

Once you're ready, we'll move onto adding a [repository](6-repository.md) for
the datasource.

### Navigation

Previous step: [Add your Todo model](4-todo-model.md)
Expand Down
20 changes: 16 additions & 4 deletions packages/example-getting-started/docs/6-repository.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
### Create your repository

The repository pattern is one of the more fundamental differences between
LoopBack 3 and 4. In 3, you would use the model class definitions themselves
to perform CRUD operations. In LoopBack 4, the layer responsible for this has
been separated from the definition of the model itself, into the repository
layer.

Create another folder in `src` called `repositories` and inside of that folder,
create two files:
- `index.ts` (our export helper)
- `todo.repository.ts`

Our TodoRepository will contain a small base class that uses the
`DefaultCrudRepository` class from `@loopback/repository` and will define the
model type we're working with, as well as its ID type. We'll also inject our
datasource so that this repository can connect to it when executing data
operations.
`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. We'll
also inject our datasource so that this repository can connect to it when
executing data operations.

#### src/repositories/todo.repository.ts
```ts
Expand All @@ -26,6 +33,11 @@ export class TodoRepository extends DefaultCrudRepository<
}
}
```

Now we have everything we need to perform CRUD operations for our Todo list,
we'll need to build the [Controller](7-controller.md) to handle our incoming
requests.

### Navigation

Previous step: [Add a datasource](5-datasource.md)
Expand Down
17 changes: 16 additions & 1 deletion packages/example-getting-started/docs/7-controller.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Now, we'll create a controller to handle our Todo routes. Create the
- `index.ts` (export helper)
- `todo.controller.ts`

In addition to creating the CRUD methods themselves, we'll also be adding
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.

Expand Down Expand Up @@ -64,6 +64,21 @@ export class TodoController {
}
```

The controller example brings together quite a few of the modules and concepts
we put together in the previous steps!
- The `@repository` decorator injects an instance of our `TodoRepository` to
provide us with the CRUD functions we need for our Todo lists
- The REST decorators (`@get`, `@post`, `@put`, `@patch`, `@del`) setup the
routing logic so that requests with the appropriate HTTP verb and route call
the correct functions
- The `@param` decorator and its other namespaced decorators (like
`@param.body`) set up all of the metadata required for injection of
parameters from the body, path, and query string of the request into our target
functions.

Now that we've wired up the controller, our last step is to tie it all into the
[Application](8-putting-it-together.md)!

### Navigation

Previous step: [Add a repository](6-repository.md)
Expand Down
65 changes: 40 additions & 25 deletions packages/example-getting-started/docs/8-putting-it-together.md
Original file line number Diff line number Diff line change
@@ -1,61 +1,73 @@
### Putting it all together

Now that we've got all of our artifacts made, let's set them up in our
application!
We've got all of our artifacts now, and all that's left is to bind them to our
[Application](http://loopback.io/doc/en/lb4/Application.html) so that LoopBack's
[Dependency injection](http://loopback.io/doc/en/lb4/Dependency-injection.html)
system can tie it all together for us!

We'll define a new helper function for setting up the repositories, as well
as adding in our new controller binding.
We'll define a new helper function for setting up the repositories, and
LoopBack's [boot module](https://github.com/strongloop/loopback-next/tree/master/packages/boot) will
take care of the other artifacts for us!

#### src/application.ts
```ts
import {ApplicationConfig} from '@loopback/core';
import {RestApplication} from '@loopback/rest';
import {TodoController, PingController} from './controllers';
import {TodoRepository} from './repositories';
import {db} from './datasources/db.datasource';

/* tslint:disable:no-unused-variable */
// Do not remove!
// Class and Repository imports required to infer types in consuming code!
// Binding and Booter imports are required to infer types for BootMixin!
import {BootMixin, Booter, Binding} from '@loopback/boot';
import {
Class,
Repository,
RepositoryMixin,
DataSourceConstructor,
RepositoryMixin,
} from '@loopback/repository';
import {db} from './datasources/db.datasource';
import {TodoRepository} from './repositories';
/* tslint:enable:no-unused-variable */

export class TodoApplication extends RepositoryMixin(RestApplication) {
export class TodoApplication extends BootMixin(
RepositoryMixin(RestApplication),
) {
constructor(options?: ApplicationConfig) {
super(options);
this.setupControllers();
this.projectRoot = __dirname;
this.setupRepositories();
}

setupControllers() {
this.controller(TodoController);
this.controller(PingController);
}

// Helper functions (just to keep things organized)
setupRepositories() {
// This will allow you to test your application without needing to
// use the "real" datasource!
const datasource =
this.options && this.options.datasource
? new DataSourceConstructor(this.options.datasource)
: db;
this.bind('datasource').to(datasource);
this.repository(TodoRepository);
}
}
}}
```

### Try it out

Now that your app is ready to go, try it out with your favourite REST client!
Start the app (`npm start`) and then make some REST requests:
- `POST /todo` with a body of `{ "title": "get the milk" }`
- `GET /todo/1` and see if you get your Todo object back.
- `PATCH /todo/1` with a body of `{ "desc": "need milk for cereal" }`
Let's try out our application!
First, you'll want to start the app.
```
$ npm start
Server is running on port 3000
```

### Navigation
Next, you can use the [API Explorer](http://loopback.io/api-explorer/?url=http://localhost:3000/swagger.json) to browse your API and make requests!

Previous step: [Add a controller](7-controller.md)
Here are some requests you can try:
- `POST /todo` with a body of `{ "title": "get the milk" }`
- `GET /todo/{id}` using the ID you received from your `POST`, and see if you
get your Todo object back.
- `PATCH /todo/{id}` with a body of `{ "desc": "need milk for cereal" }`

That's it! You've just created your first LoopBack 4 application!

### More examples and tutorials

Expand All @@ -64,3 +76,6 @@ Eager to continue learning about LoopBack 4? Check out our
section to find examples for creating your own custom components, sequences and
more!

### Navigation

Previous step: [Add a controller](7-controller.md)

0 comments on commit 020e9b8

Please sign in to comment.