Originally published on strongloop.com
As the weather starts to warm up for summer, the LoopBack team has turned up the heat on the milestone tasks we planned for the month of May and beyond. We worked on areas such as:
- Improving our documentation pages and API documentation.
- Giving users unified website experience on
loopback.io
. - Making CI green across connector repositories and being able to test juggler 3.x and 4.x with connectors.
- Implementation of Interceptors in the LoopBack framework.
- Authentication extension point, refactoring authentication action, and using the new features in shopping example repository.
- Inclusion of related models in model relations.
- Testing out ways to roll out experimental features.
These are just the tip of the iceberg. Read on to find out more on what the LoopBack team accomplished this month.
Method Interceptor Support
Interceptors are reusable functions to provide aspect-oriented logic around method invocations. There are many use cases for interceptors, such as:
- Add extra logic before / after method invocation. For example, logging or measuring method invocations.
- Validate/transform arguments.
- Validate/transform return values.
- Catch/transform errors. For example, normalize error objects.
- Override the method invocation. For example, return from cache.
See PR#2687 for more details.
Binding Configuration
To allow bound items in the context to be configured, we introduced some conventions and corresponding APIs to make it simple and consistent in PR#2259.
We treat configurations for bound items in the context as dependencies, which can be resolved and injected in the same way of other forms of dependencies. For example, the RestServer
can be configured with RestServerConfig
.
New Mounted LoopBack 3 Application in LoopBack 4 Example
We introduced a new example that illustrates mounting an existing LoopBack 3 application in a LoopBack 4 project. We took the CoffeeShop
application from loopback-getting-started and mounted it in a new LoopBack 4 project. The endpoints, including the OpenAPI spec, have also been mounted in the project. You can check out the example by running lb4 example lb3-application
.
Model Definitions Reference in Operation Spec
Controller methods can now reference model definitions through OpenAPI spec. This replaces the need to use x-ts-type
extension to reference model schema. In addition, if an operation defines the model, another operation can reference that model without defining it.
For example, in the following code snippet, since the Todo
model definition is provided by @get('/todos')
, @get('/todos/{id')
can now also reference it without defining it.
class MyController {
@get('/todos', {
responses: {
'200': {
description: 'Array of Category model instances',
content: {
'application/json': {
schema: {
$ref: '#/definitions/Todo',
definitions: {
Todo: {
title: 'Todo',
properties: {
title: {type: 'string'},
},
},
},
},
},
},
},
},
})
async find(): Promise<object[]> {
/* … */
}
@get('/todos/{id}', {
responses: {
'200': {
description: 'Todo model instance',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/Todo',
},
},
},
},
},
},
})
async findById(): Promise<object> {
/* … */
}
}
To make model references even easier to use, we have also introduced a new helper getModelSchemaRef
which builds a $ref
entry with accompanied schema in definitions
from the given model instance. See PR#2971.
class MyController {
@get('/todos', {
responses: {
'200': {
description: 'Array of Category model instances',
content: {
'application/json': {
schema: getModelSchemaRef(Todo),
},
},
},
},
})
async find(): Promise<object[]> {
/* … */
}
@get('/todos/{id}', {
responses: {
'200': {
description: 'Todo model instance',
content: {
'application/json': {
schema: getModelSchemaRef(Todo),
},
},
},
},
})
async findById(): Promise<object> {
/* … */
}
}
In the near future, we would like to leverage this new mechanism to emit different model schema for different API endpoints:
- Response schema of
find
andfindById
endpoints should include navigational properties for related models. - Response schema of
create
endpoint should excludeid
and any other database-generated properties (e.g._rev
in CouchDB/Cloudant). - Response schema of
updateById
andupdateAll
endpoints should mark all model properties as optional.
Better Formatting of Model Settings Object in Scaffolded Files
PR#2843 improved the way how our CLI tool serialized model settings to TypeScript code.
Before this change, model settings object was converted to JSON, which produced non-idiomatic TypeScript code. For example:
@model({ settings: {"mongodb": {"collection": "clients"}}})
export class MyModel extends Entity {
// ...
}
Now we convert the object into TypeScript object definition. See below for an example:
@model({
settings: {
mongodb: {collection: 'clients'},
}
})
export class MyModel extends Entity {
// ...
}
dataType: 'ObjectID' for MongoDB Connector
You can set a model property's mongodb
property definition dataType
to "ObjectID" to enforce ObjectID coercion irrespective of the strictObjectIDCoercion
setting.
In the following example, the id
and xid
will be coerced to ObjectID
even if strictObjectIDCoercion
is set to true.
const User = ds.createModel(
'user',
{
id: {type: String, id: true, mongodb: {dataType: 'ObjectID'}},
xid: {type: String, mongodb: {dataType: 'ObjectID'}}
},
{strictObjectIDCoercion: true}
);
For more details, see PR#517.
Authentication
This month we implemented a PoC PR to illustrate plugging in the passport strategy in the new published @loopback/autthentication
module. The PR proves the new authentication action is able to verify a request with both passport based and non passport based strategy. Therefore we just deprecated the old passport adapter in story 2467, and focus on the new adapter creation in story 2311.
The initial proposal for the new adapter is wrapping each configured strategy instance so that it fits the AuthenticationStrategy
interface. Raymond suggested exploring another approach which applies a wrapper to the passport
module itself. And since the team is discussing the work flow of incrementally adding a new feature, Miroslav suggested moving the new passport adapter to a standalone experimental module along with the comparison between two proposals. Eventually the adapter will be a component that can be plugged into @loopback/authentication
.
Experimental Feature Development
We've introduced experimental features to achieve a balance between the high code quality and the development speed.
At first we tried keeping the lab packages in a mirror repository loopback-labs
for the purpose of isolation, then graduate the features into loopback-next
when they are production ready. During the spike, we realized a better way to isolate each feature: create and release each feature from its own branch, so that features are independent from each other and have their own life cycle. The releasing process is also simpler since it only targets on one package. With this in mind, and considering the synchronization effort between two repositories, we decided to keep lab packages stay in loopback-next
.
The work flow of adding an experimental package is documented in https://github.com/strongloop/loopback-next/blob/labs/base/LABS.md. It explains how to create your experimental feature branch, incrementally improve the code and graduate the package.
Documentation
We took some time to rework outdated sections of our documentation pages in May. First of all, we updated docs on how to create stub services for controller unit tests. At the same time, we updated the status of auto-generated smoke test section and top-down application building. See PR#2879 for more details. Moreover, our hasOne relation page also had some typos and errors and we were able to address them in PR#2959.
In PR#2944, we revamped the Sequences documentation page with information on what happens behind the scenes for some of the sequence actions like invoke
and send
. We also added details on how to retrieve query string parameters.
We added a new Components page to explain the shape and concept of components for extensibility as well as how they contribute artifacts to a LoopBack 4 application. For more details, check out PR#2702 and PR#2361.
In PR#2834, we introduced @loopback/tsdocs
package which provides API Docs for the rest of the LB4 packages in our loopback-next
monorepo using Microsoft's api-extractor
and api-documenter
tools. It also integrates the generated API Docs for consumption in loopback.io
. You can see them live here.
Examples for New LoopBack 4 Artifacts/ Concepts
We added a new greeting-app that shows how to compose an application from component and controllers, interceptors, and observers. The application is built on top of example-greeter-extension and can greet users in different languages. It has a caching interceptor to handle multiple requests for the same payload (name and language) within a specific time. See PR#2941 for more details.
On the same note, we added standalone examples for @loopback/context
showing how to use the module as an Inversion of Control (IoC) and Dependency Injection (DI) container. We covered a wide array of usages for the utilities provided by the module such as context chaining, binding types, and customizing injection decorators/resolvers.
Unified Web Site Experience on loopback.io
We created the dedicated web site for LoopBack 4 last year. Now that LoopBack 4 has become the active release, we are moving the LoopBack 4 pages back to loopback.io web site.
In the meantime, we're actively attempting to rebuild the “Who’s using LoopBack” section to showcase our users and the use cases. If you would like to be a part of it, please sign up here!
Other Changes
PR#2856 fixed REST API Explorer to correctly handle both
basePath
configuration specified at LoopBack application/server level andmountPath
provided by Express when the LB app is mounted on an Express application.PR#2823 improved the OpenAPI spec emitted for LoopBack 3 models when the entire LB3 application is mounted in LB4 project. In particular, the schema for request bodies of "create" requests now excludes
id
(primary key) properties when the model is configured withforceId: true
(which is the default).Keeping dependencies up-to-date is time consuming, especially in monorepos. Originally, we were used GreenKeeper to automate the task. Unfortunately, GreenKeeper does not support the combination of lerna monorepos with package-locks enabled (see greenkeeper#1080).
In May, we migrated our Shopping example app to RenovateBot. The migration went well, and we are now migrating the main loopback-next monorepo too.
PR#3013 removed implicit dependency of
@loopback/testlab
on@types/mocha
. This dependency was preventing LoopBack projects to use Jest test framework instead of Mocha. Now that the fix was landed and published to npm registry,@loopback/testlab
should work with any test framework that providesit
andit.skip
APIs.PR#2996 makes sure we stay current with TypeScript and upgrades our project to use version
3.5.1
.
LoopBack 3
Node.js 6 went end-of-life at the end of April. We are incrementally removing it from our CI build configurations and updating our package.json
files to bump up the minimum supported version to Node.js 8.
When we introduced version 4 of loopback-datasource-juggler back in 2018, we did not update connector repositories to run tests against this new juggler version too. As a result, we were encountering failed builds when back-porting pull requests from juggler 4.x to 3.x. We looked into different ways how to address this problem and decided to go with a solution where a single connector run shared tests from multiple loopback-datasource-juggler versions. Some of the connectors have been already updated, we will be updating the rest in the next months.
Additional changes:
generator-loopback
: The version of the Node.js engine is updated to >= 8 because Node.js 6 entered EOF in April 2019.generator-loopback
: We fixed two regression bugs to honour the name argument of commandlb swagger
andlb boot-script
.loopback-passport-component
: We landed a community PR to support user ldap profile configuration with group search for Microsoft active directory, you can check the details in PR #267.loopback-connector-cloudant
: The CI failures are fixed after upgrading the dependency version toloopback-connector-couchdb2@1.4.0
.
Call to Action
LoopBack's future success depends on you. We appreciate your continuous support and engagement to make LoopBack even better and meaningful for your API creation experience. Please join us and help the project by:
- Reporting issues.
- Contributing code and documentation.
- Opening a pull request on one of our "good first issues".
- Joining our user group.