Loopback-next: WARNING: relational database doesn't support {strict: false} mode. {strict: true} mode will be set for model instead.

Created on 5 Feb 2020  路  12Comments  路  Source: strongloop/loopback-next

Steps to reproduce

Use {strict: false} in @model(settings : {}) property.

Current Behavior

Getting

WARNING: relational database doesn't support {strict: false} mode. {strict: true} mode will be set for model User instead.

Expected Behavior

The warning should not be here. As I updated the loopback cli and with that I updated loopback dependencies, after updating everything, I am getting this warning. It working fine in previous version. Using MySQL. Also getting these warnings if I get request on any URL.

Additional information

+-- @loopback/[email protected]
+-- @loopback/[email protected]
+-- @loopback/[email protected]
+-- @loopback/[email protected]
+-- @loopback/[email protected]
+-- @loopback/[email protected]
+-- @loopback/[email protected]
+-- @loopback/[email protected]
+-- @loopback/[email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]

Juggler

Most helpful comment

@UsmanJavedAttari if I understand your use case correctly, your model contains well-defined property (via @property()) that are stored in your MySQL database, but then you have some custom code that's adding additional properties to be returned in HTTP responses. When a HTTP request to create or modify a model includes those additional properties, they are silently discarded by LoopBack and that's the behavior you are looking for.

Is my description correct?

Where are you adding the extra properties to the response, is it in your controller method?

My recommendation is to convert your model to a plain data object first, and then add the extra properties.

class MyController {
  @get(/*...*/)
  async find(
    @param.query.object('filter', getFilterSchemaFor(TodoList))
    filter?: Filter<TodoList>,
  ): Promise<TodoList[]> {
    const result = this.todoListRepository.find(filter);
    return result.map(it => {
      const data = it.toJSON();
      // add your extra properties here
      return data;
    });
  }
}

There is a catch though: the OpenAPI spec will not describe the additional properties. I believe your original implementation has this problem too. A better solution is to create a new model class for your response data and explicitly describe the properties you are adding on top of the persisted data.

@model()
class CustomerResponse extends Customer {
  // all Product properties are inherited
  // let's add some extra data now
  @property()
  fullName: string;

  // we can fill extra properties in the constructor (for example)
  constructor(data: Partial<Customer>) {
    super(data);
    this.fullName = this.firstName + ' ' + this.lastName;
  }
}

class CustomerController {
  @get(
    // use schema: getModelSchemaRef(CustomerResponse, {includeRelations: true})
  )
  async find(
    // important! the filter object does not accept "extra" properties, 
   // create the filter schema using the base model class
    @param.query.object('filter', getFilterSchemaFor(Customer))
    filter?: Filter<Customer>,
  ): Promise<CustomerResponse[]> {
    const result = this.customerRepository.find(filter);
    return result.map(it => new CustomerResponse(it));
  }
}

All 12 comments

working fine in previous version

I don't think it actual does anything for non-relational dbs. Does anything change when you don't set {strict: false}?

See: https://github.com/strongloop/loopback-datasource-juggler/pull/1817

@agnes512 Is this correct?

Yes. Because {strict: false} mode is only supported by NoSQL databases. See https://github.com/strongloop/loopback-next/issues/4042 and https://github.com/strongloop/loopback-next/issues/4042#issuecomment-549801710.

Hey @UsmanJavedAttari

Please remove {strict: false} from @model(settings : {}) property to remove the warning.

@dougal83 then I am not able to add extra properties.
Let's say I want to add some extra properties in the response, I have to add those in model and make {strict: false}. Otherwise, it doesn't pick extra properties.

And the question is why I didn't get any warnings in the previous version?馃 Even though I was using {strict: false}.

The warning was added lately. We didn't change anything but add the warning.

@dougal83 then I am not able to add extra properties.
Let's say I want to add some extra properties in the response, I have to add those in model and make {strict: false}. Otherwise, it doesn't pick extra properties.

What about this?

@UsmanJavedAttari if I understand your use case correctly, your model contains well-defined property (via @property()) that are stored in your MySQL database, but then you have some custom code that's adding additional properties to be returned in HTTP responses. When a HTTP request to create or modify a model includes those additional properties, they are silently discarded by LoopBack and that's the behavior you are looking for.

Is my description correct?

Where are you adding the extra properties to the response, is it in your controller method?

My recommendation is to convert your model to a plain data object first, and then add the extra properties.

class MyController {
  @get(/*...*/)
  async find(
    @param.query.object('filter', getFilterSchemaFor(TodoList))
    filter?: Filter<TodoList>,
  ): Promise<TodoList[]> {
    const result = this.todoListRepository.find(filter);
    return result.map(it => {
      const data = it.toJSON();
      // add your extra properties here
      return data;
    });
  }
}

There is a catch though: the OpenAPI spec will not describe the additional properties. I believe your original implementation has this problem too. A better solution is to create a new model class for your response data and explicitly describe the properties you are adding on top of the persisted data.

@model()
class CustomerResponse extends Customer {
  // all Product properties are inherited
  // let's add some extra data now
  @property()
  fullName: string;

  // we can fill extra properties in the constructor (for example)
  constructor(data: Partial<Customer>) {
    super(data);
    this.fullName = this.firstName + ' ' + this.lastName;
  }
}

class CustomerController {
  @get(
    // use schema: getModelSchemaRef(CustomerResponse, {includeRelations: true})
  )
  async find(
    // important! the filter object does not accept "extra" properties, 
   // create the filter schema using the base model class
    @param.query.object('filter', getFilterSchemaFor(Customer))
    filter?: Filter<Customer>,
  ): Promise<CustomerResponse[]> {
    const result = this.customerRepository.find(filter);
    return result.map(it => new CustomerResponse(it));
  }
}

@UsmanJavedAttari It is possible to extend a model in the controller as follows:

@model()
export class CustomUserResponse extends User {
  @property({
    type: 'string',
    required: true,
  })
  extendedProp: string;
}

And make the required changes:

@post('/users', {
    responses: {
      '200': {
        description: 'User',
        content: {
          'application/json': {
            schema: {
              'x-ts-type': CustomUserResponse,
            },
          },
        },
      },
    },
  })
  async create(
    // ...
  ): Promise<CustomUserResponse> {
      // ...
      const savedUser = await this.userRepository.create() // ...
      // ...
      return Object.assign({ extendedProp: 'example' }, savedUser);
  }

Lol. Just beaten. :)

Closing as solved, and due to inactivity.

I saw the same warning when I generated my models using LB4 CLI for PostgreSQL.

Yes. Because {strict: false} mode is only supported by NoSQL databases. See #4042 and #4042 (comment).

Both of us (@UsmanJavedAttari) use RDBMS not NoSQL!

Please remove {strict: false} from @model(settings : {}) property to remove the warning.

Because I use RDBMS connector I expect from LB4 CLI generating a model without {strict: false}; Why I need to modify it manually?!
Am I right?
If yes; Please reopen this issue.

It's considered a non-issue as RDBMS connectors will ignore it and there's no material problems caused.

The warning was added as a heads up to developers that the setting will be ignored. This was to prevent developers from wasting time debugging why the setting has no effect.

It's not a critical error, it's purely informational and the original behaviour before the warning was added was not changed.

I expect from LB4 CLI generating a model without {strict: false};

I'm guessing this is with regard to lb4 discover? It's added so that the Model definition functions as close as possible to the original database schema, even if it's used on a NoSQL database.

It's intended for workflows where lb4 discover was used and the generated Model was then used with a NoSQL database.

Since lb4 discover is meant to create a Model definition that is "as correct as possible" irregardless of what type of database is used, it's functioning as intended.

Why I need to modify it manually?!

You don't need to remove it. It will be safely ignored by the RDBMS and function identically as if the setting was never there.

Was this page helpful?
0 / 5 - 0 ratings