Skip to content
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

MySQL: can't GET relations in response after first npm start #3356

Closed
gonzarascon opened this issue Jul 15, 2019 · 13 comments
Closed

MySQL: can't GET relations in response after first npm start #3356

gonzarascon opened this issue Jul 15, 2019 · 13 comments
Assignees
Labels

Comments

@gonzarascon
Copy link

gonzarascon commented Jul 15, 2019

Hello!

I just finished the Todo-List Tutorial from the documentation and implemented the Model/Repository relation as the tutorial shows, the only diference between it and my project it's that I have been using a local MySQL server from the beginning, so I created my Models based on the MySQL tables.

In my project I have the next relation => A User can have many Courses.

At the first start of the app, when I requested /courses with GET, the endpoint responded correctly with an array of objects (Courses) and inside of each object, another object with the user that created that Course. That was fine because I wanted so to happen.

Now, from the second time I did npm start (With no changes either on the Models or Repositories), when I request /courses with GET, the endpoint only respond with an array of Courses with no data about Users.

This is an strange bug because the endpoint's Example Value and Schema shows the correct structure:

{
    /*... Other props from Courses*/
    "user": {
      "id": 0,
      "xp": 0,
      "user_type": "string",
      "badges": {},
      "titles": {},
      "username": "string",
      "email": "string",
      "password": "string",
      "user_photo": "string",
      "state": "string",
      "courses": [
        null
      ]
    }
  }   

I looked for similar situations, but I could not find any!

@gonzarascon gonzarascon changed the title MySql relations do not come in response after first npm start MySQL: can't GET relations in response after first npm start Jul 16, 2019
@dhmlau
Copy link
Member

dhmlau commented Jul 16, 2019

@nabdelgadir, could you please take a look? Thanks.

@gonzarascon
Copy link
Author

More information about this: I also tried running npm run migrate into a new schema for test this bug and it still does not work.

@nabdelgadir
Copy link
Contributor

Thanks for reporting this issue. We couldn't reproduce it on our end. For us, the /courses endpoint only returned the user id and not the user object. Perhaps we set up the relations slightly differently. Would you mind giving us a sample repo to reproduce your problem? See https://loopback.io/doc/en/contrib/Reporting-issues.html#loopback-4x-bugs, thanks!

@gonzarascon
Copy link
Author

gonzarascon commented Jul 17, 2019

@nabdelgadir That's exactly the bug that I found! /courses does not return the user object although Swagger UI shows that object in the Example Value section.
The funny thing is /courses returns the user object at the first npm start after the repository/model/controler configuration. After that first start, the endpoint only returns the user id
Sure, I’ll work on a sample repo to try to reproduce this ;)

@nabdelgadir
Copy link
Contributor

@gonzarascon Thank you! And that's very strange. Using the explorer, it showed us the schema with the user object but it just returned the id too. The only difference is we never saw the object being returned the first time after running npm start.

@gonzarascon
Copy link
Author

Hey @nabdelgadir ! I started to work on the repository for reproducing this bug using the todo-list example and guess what? After running npm start (with no modifications on the code), and requested GET to the /todos endpoint, it only returns the Todo-List id instead of the Todo-List object!

I'm suspecting it could be a problem with the @hasMany and @belongsTo decorators, maybe?

I'll try riding off all cached data on my PC in case there's a problem with that.

@nabdelgadir
Copy link
Contributor

nabdelgadir commented Jul 19, 2019

@gonzarascon I see where the confusion is coming from. So specifically for the TodoList example, we introduced temporary inclusion so that the schema currently includes the todoList object if you include the filter {include: [{relation: 'todo-lists'}]} when doing GET /todos (see #3171 if you're interested).

However, in your case, we still don't support inclusion of related models so you won't see the User object when doing GET /courses. We actually currently have a SPIKE open (#3387) for this feature.

But, if you need inclusion now, you can hardcode it similar to how we did it in our TodoList example. See the find and findById functions in todo.repository.ts and todo-list.repository.ts.

Let me know if you have any other questions. 😄

@gonzarascon
Copy link
Author

@nabdelgadir oh, I see... But, when I ran the TodoList example, the relations didn't work either. Could it be some sort of problem with loopback caching data that is replicating the issue in other projects?
In my project I copied the harcoded relation from the TodoList (doing the proper modifications to work with my models, respositories and controllers) as I understood that this feature isn't yet supported. It's strange that, the first time I did npm start the relations worked as expected, but after that they seem to be lost or something although the code wasn't changed 🤔

@nabdelgadir
Copy link
Contributor

@gonzarascon Did you remember to use the filter when doing your GET requests e.g. {include: [{relation: 'todo-lists'}]}? And yes, I agree it's strange you got it the first time. I don't know why it happened, but I hope someone else can chime in if they know how that was possible.

@bajtos @strongloop/sq-lb-apex

@gonzarascon
Copy link
Author

gonzarascon commented Jul 19, 2019

@nabdelgadir Do you have any example on how to implement {include: [{relation: 'todo-lists'}]} ? At the moment I copied, as the TodoList example shows, getModelSchemaRef(TodoList, {includeRelations: true}) inside the @get decorator for /todo-lists.
I looked for {include: [{relation: 'todo-lists'}]} inside of the TodoList example and only found that code in the _tests_ folder.

@nabdelgadir
Copy link
Contributor

nabdelgadir commented Jul 22, 2019

@gonzarascon {include: [{relation: 'todo-lists'}]} is a filter, so when you do the request, you can include it in the url e.g. http://127.0.0.1:3000/todos?filter[include][][relation]=todoList. If you want it by default, you can modify the find method. This is our current one in the TodoList example (in todo.repository.ts) (sorry about the formatting):

async find(
    filter?: Filter<Todo>,
    options?: Options,
  ): Promise<TodoWithRelations[]> {
    // Prevent juggler for applying "include" filter
    // Juggler is not aware of LB4 relations
    const include = filter && filter.include;
    filter = {...filter, include: undefined};

    const result = await super.find(filter, options);

    // poor-mans inclusion resolver, this should be handled by DefaultCrudRepo
    // and use `inq` operator to fetch related todo-lists in fewer DB queries
    // this is a temporary implementation, please see
    // https://github.com/strongloop/loopback-next/issues/3195
    if (include && include.length && include[0].relation === 'todoList') {
      await Promise.all(
        result.map(async r => {
          // eslint-disable-next-line require-atomic-updates
          r.todoList = await this.todoList(r.id);
        }),
      );
    }

  return result;
}

You can simplify it to the following so you don't need the filter and it includes them by default:

async find(
    filter?: Filter<Todo>,
    options?: Options,
  ): Promise<TodoWithRelations[]> {
    // Prevent juggler for applying "include" filter
    // Juggler is not aware of LB4 relations
    filter = {...filter, include: undefined};

    const result = await super.find(filter, options);

    // poor-mans inclusion resolver, this should be handled by DefaultCrudRepo
    // and use `inq` operator to fetch related todo-lists in fewer DB queries
    // this is a temporary implementation, please see
    // https://github.com/strongloop/loopback-next/issues/3195
      await Promise.all(
        result.map(async r => {
          // eslint-disable-next-line require-atomic-updates
          r.todoList = await this.todoList(r.id);
        }),
      );

    return result;
  }

Let me know if this helps. 😄

@gonzarascon
Copy link
Author

gonzarascon commented Jul 23, 2019

@nabdelgadir thank you very much! So far, I tried all three options: including the filter in the url, modifying the find method with filter and modifying the find method without the filter.
The one that worked for me (in the meantime at least), was including the filter in the url. Although I see this option as the most uncomfortable of all, it's the only that works without problem and I'm going to explain why:
In my case I need the API to return any relations that the current endpoint I'm doing GET has. For example: /courses has a relation with /users (a course belongs to an user), so I need to have an user object in every course object that I'm getting through GET (the endpoint /courses returns an array of courses objects). At the same time, I need to have a courses object when doing GET to /users.

So, if I had a filter as the todoList example shows, the API won't return any relations after the first npm start. Removing the filter (as @nabdelgadir showed above) worked just fine, but I couldn't remove the filter in both repositories as, when doing GET to /courses, the find method at /users will also fetch for /courses entering in a loop.

In conclussion to this brief explanation, I'll stick to the URL method for now and I hope the relations feature to be supported soon!

Thank you @nabdelgadir for all your help!

@nabdelgadir
Copy link
Contributor

@gonzarascon Thank you for the explanation! I'm going to close this issue, but if you have any further questions, feel free to ask. 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants