Search code examples
jsonlaravelvue.jsrestapi-design

Best practice for structuring JSON for models with foreign key relationships?


Hello! I am working on a mono-repo using Laravel and VueJS, and it makes CRUD operations on tables containing foreign keys.

I'm finding it difficult to come up with a pattern or structure for my JSON. I've looked through different resources without much luck.

Here is an example which hopefully conveys my question: For example, the table users has column language_id which ties it to the languages table.

Assume the user is filling out multiple forms, one of which where they select their language from a dropdown with the language IDs in it.

Since my User model has the language relationship and $fillable property language_id, it seems I always need the PUT/POST api payload to match the model/table, like this:

// POST/PUT payload
{
   language_id: 3,        // foreign key column
   first_name: 'Fred',    // string column
}

But, for other purposes on the frontend, I want to know the language name with that user resource. So my other option is to have my UserResource and StoreUserRequest files like so:

// UserResource/StoreUserRequest/JSON format
{
   language: {
      id: 3,             // $this->language_id
      name: 'English',   // $this->language->name
   },
   first_name: 'Fred',
}

If I take that approach, it seems as though I need to massage the structure of the data before passing it back to the backend in a POST or PUT.

Another option was to just add new fields to the UserResource file with the information I need. For example,

{
   language_id: 3,        // $this->language_id
   language: 'English',   // $this->language->name
   first_name: 'Fred',    // $this->first_name
}

But I'm not sure if this a good approach. I'm working on what I think is a medium-size project (100+ tables), and would love to hear what everyone thinks! Thanks!

I've tried using search engines to find my answer, but the best I've got is "it depends". I'm not sure how to better describe my problem.


Solution

  • The best practice for you is to use :

    {
       language: {
          id: 3,             // $this->language->id
          name: 'English',   // $this->language->name
       },
       language_id:3, // $this->language_id
       first_name: 'Fred', // $this->first_name
    }
    

    When you will be familiar with Laravel relationship you see how easier is it. Without thinking about laravel, but only in JSON API, when dealing with different object linked together (here a user and a langage) you should not mix their parameters on the same level. I give you another example with more depth. Fred now has a father : Peter and Peter speaks the same langage as Fred (But can obviously be different). A complete JSON of Peter should be :

    {
       first_name: 'Peter', // 
       id: 12,
       parent_id: null, // $this->parent_id (forgive me but i assume their is only one parent for the example and here peter do not have parent)
       language: {
          id: 3,             // $this->language->id
          name: 'English',   // $this->language->name
       },
       children: [{
          language: {
             id: 3,             // $this->children[0]->language->id
             name: 'English',   // $this->children[0]->language->name
          },
          language_id: 3, // $this->language_id
          first_name: 'Fred', // $this->first_name
          parent_id: 12, // $this->children[0]->parent_id
          id: 23 // $this->children[0]->id
       }]
    }
    
    

    The aim of this is to isolate each object in order to keep a clean code and to reuse it easier.

    In a second hand if your developping a very specific use-case that will not evolve and will not be used even later by other use-cases, you can use an less clean way by dispatching every element on the same level. But keep in mind that most of the time things that evolves were developped as thing that will not be evolving (sadly...). In practical terms, you can but you shouldn't