-
Notifications
You must be signed in to change notification settings - Fork 383
Add best practices for bottom up approach #624
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
0a2555f
add best practices for bottom up
shimks 29499ac
apply feedback
shimks adae173
add tutorial links
shimks 5fae1c4
change titles of bottom-up top-down
shimks c37259c
change defining-the-api to -app
shimks 6f38886
change to design-first
shimks 2e52996
switch to openapi-v3
shimks File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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
186 changes: 186 additions & 0 deletions
186
pages/en/lb4/Defining-the-API-using-code-first-approach.md
This file contains hidden or 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,186 @@ | ||
| --- | ||
| lang: en | ||
| title: 'Defining the API using code-first approach' | ||
| keywords: LoopBack 4.0, LoopBack 4 | ||
| tags: | ||
| sidebar: lb4_sidebar | ||
| permalink: /doc/en/lb4/Defining-the-API-using-code-first-approach.html | ||
| summary: | ||
| --- | ||
|
|
||
| ## Define the API from code-first approach | ||
|
|
||
| You may want to build your application from the 'bottom up' if you: | ||
|
|
||
| * do not have a complete understanding of what your existing tools can offer. | ||
| * want to capture already existing domain models so that they can be reflected | ||
| as APIs for external consumption. | ||
| * need to grow and change your API from the initial implementation | ||
| * want to set up and run an API from an early stage of the production to | ||
| easily envision the big picture of the end product. | ||
|
|
||
| There are various tools available to LoopBack which allows this bottom-up | ||
| approach of building your application to be simple through the usages of | ||
| metadata and decorators. | ||
|
|
||
| ### Start with LoopBack artfiacts | ||
|
|
||
| With TypeScript's [experimental decorator](https://www.typescriptlang.org/docs/handbook/decorators.html) | ||
| feature, APIs can be automatically built and exposed as your application | ||
| continues development. Some key concepts utilize decorators to gather | ||
| _metadata_ about your code and then assemble them into a valid OpenAPI | ||
| specification, which provide a description of your API. | ||
| These concepts and their decorators include: | ||
|
|
||
| * [Model](Model.html) | ||
| * `@model()` | ||
| * `@property()` | ||
| * [Routes](Routes.html) | ||
| * `@operation()` | ||
| * `@param()` | ||
|
|
||
| ### Define your models | ||
|
|
||
| Your models act as common definitions between data being handled by the API | ||
| layer and the datasource layer. Since your API is going to be built around the | ||
| manipulation of models and their properties, they will be the first to be | ||
| defined. | ||
|
|
||
| {% include note.html content=" | ||
| `Todo` model from [tutorial](https://github.com/strongloop/loopback-next/blob/master/packages/example-getting-started/docs/model.md#srcmodelstodomodelts) | ||
| is used for demonstration here. | ||
| " %} | ||
|
|
||
| First, write a simple TypeScript class describing your model and its | ||
| properties: | ||
|
|
||
| {% include code-caption.html content="src/models/todo.model.ts" %} | ||
|
|
||
| ```ts | ||
| export class Todo { | ||
| id?: number; | ||
| title: string; | ||
| desc?: string; | ||
| isComplete: boolean; | ||
| } | ||
| ``` | ||
|
|
||
| To this representation of your model, we can use the `@model` and `@property` | ||
| decorators to create the model's _metadata_; a model definition. | ||
| LoopBack and LoopBack extensions can use this model definition for | ||
| a wide variety of uses, such as: | ||
|
|
||
| * generating OpenAPI schema for your APIs | ||
| * validating instances of the models during the request/response lifecycle | ||
| * automatically inferring relationships between models during datasource | ||
| operations | ||
|
|
||
| To apply these decorators to your model, you simply prefix the class definition | ||
| with the `@model` decorator, and prefix each property with the | ||
| `@property` decorator: | ||
|
|
||
| {% include code-caption.html content="src/models/todo.model.ts" %} | ||
|
|
||
| ```ts | ||
| import {model, property} from '@loopback/repository'; | ||
|
|
||
| @model() | ||
| export class Todo { | ||
| @property() id?: number; | ||
| @property({ | ||
| required: true, | ||
| }) | ||
| title: string; | ||
| @property() desc?: string; | ||
| @property() isComplete: boolean; | ||
| } | ||
| ``` | ||
|
|
||
| ### Define your routes | ||
|
|
||
| {% include note.html content=" | ||
| `TodoController` from [tutorial](https://github.com/strongloop/loopback-next/blob/master/packages/example-getting-started/docs/controller.md#srccontrollerstodocontrollerts-2) | ||
| is used for | ||
| demonstration here. | ||
| " %} | ||
|
|
||
| Once your models are defined, create a controller to host your routes | ||
| for each [paths](https://swagger.io/specification/#pathsObject) of your API: | ||
|
|
||
| {% include code-caption.html content="src/controllers/todo.controller.ts" %} | ||
|
|
||
| ```ts | ||
| import {Todo} from '../models/todo.model'; | ||
|
|
||
| export class TodoController { | ||
| constructor() {} | ||
|
|
||
| async createTodo(todo: Todo) { | ||
| // data creating logic goes here | ||
| } | ||
|
|
||
| async findTodoById(id: number, items?: boolean): Promise<Todo> { | ||
| // data retrieving logic goes here | ||
| } | ||
|
|
||
| // ... | ||
| } | ||
| ``` | ||
|
|
||
| The controller's routes in their current state has no information on which | ||
| API endpoints they belong to. Add them in by appending `@operation` to each | ||
| method of your routes and `@param` or `@requestBody` to its parameters: | ||
|
|
||
| {% include code-caption.html content="src/controllers/todo.controller.ts" %} | ||
|
|
||
| ```ts | ||
| import {Todo} from '../models/todo.model'; | ||
| import {post, get, param, requestBody} from '@loopback/openapi-v3'; | ||
|
|
||
| export class TodoController { | ||
| constructor() {} | ||
|
|
||
| @post('/todo') // same as @operation('post', '/todo'); | ||
| async createTodo(@requestBody() todo: Todo) { | ||
| // data creating logic goes here | ||
| } | ||
|
|
||
| @get('/todo/{id}') | ||
| async findTodoById( | ||
| @param.path.number('id') id: number, | ||
| @param.query.boolean('items') items?: boolean, | ||
| ): Promise<Todo> { | ||
| // data retrieving logic goes here | ||
| } | ||
|
|
||
| // ... | ||
| } | ||
| ``` | ||
|
|
||
| Once your routes have been decorated, your application is ready to serve | ||
| its API. When an instance of `RestServer` is run, an OpenAPI specification | ||
| representing your application's API is built. The spec is generated | ||
| entirely from the decorated elements' metadata, which in turn provides | ||
| routing logic for your API when your application is running. | ||
|
|
||
| ### Reviewing your API specification | ||
|
|
||
| To review your complete API specification, run your application with the | ||
| decorated controllers registered. Once it is running, visit `/openapi.json` | ||
| endpoint to access your API specification in JSON format or `/openapi.yaml` | ||
| for YAML. Alternatively, the specification file can also be accessed | ||
| in code through the `getApiSpec()` function from your `RestServer` instance. | ||
|
|
||
| For a complete walkthrough of developing an application with the bottom-up | ||
| approach, see our [Todo application](https://github.com/strongloop/loopback-next/blob/master/packages/example-getting-started/README.md#loopbackexample-getting-started) | ||
| tutorial. | ||
|
|
||
| {% include note.html content=" | ||
| If you would like to create your API manually or already have one designed, | ||
| refer to [Defining the API using design-first approach](Defining-the-API-using-design-first-approach) | ||
| page for best practices. | ||
| " %} | ||
|
|
||
| {% include next.html content= " | ||
| [Defining your testing strategy](./Defining-your-testing-strategy.html) | ||
| " %} |
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Defining API's using code-first approachmight be better.Defining the API ...seems odd.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1. As a helpful comment though,
nevertry not to use'sto make something plural :p, even for acronyms (unless it ends with an S, then I have no clue lol).