cloudcreativity / laravel-json-api

JSON API (jsonapi.org) package for Laravel applications.
http://laravel-json-api.readthedocs.io/en/latest/
Apache License 2.0
778 stars 110 forks source link

unable to create new table entries using relationship routes. #302

Closed karlis-simanovics closed 5 years ago

karlis-simanovics commented 5 years ago

Greetings!

I am not quite sure whether this qualifies as an "issue", maybe more like a "question". Perhaps this is completely unrelated to this project entirely.

The problem: I am unable to create new table entries using relationship routes.

prerequisites: The routes used in the examples below are successfully being generated with the following code:

$api->resource('employees');

$api->resource('stores', [
        'has-many' => 'employees'
]);

What works: I am able to successfully create a new table entry through the route http://project.test/api/employees with the following json:

{
  "data": {
    "type": "employees",
    "attributes": {
      "name":"mr freeman",
      "position":"sales manager",
    },
    "relationships": {
      "store": {
        "data": {
          "type": "stores",
          "id": "1"
        }
      }
    }
  }
}

The issue: I am unable to create a table entry through the relationship route http://project.test/api/stores/1/relationships/employees with the json being the same, the only exception being the "id" field under "data":

{
  "data": {
    "type": "employees",
    "id": "1",
    "attributes": {
      "name":"mr freeman",
      "position":"sales manager",
    },
    "relationships": {
      "store": {
        "data": {
          "type": "stores",
          "id": "1"
        }
      }
    }
  }
}

The server returns the following response:

"status": "404",
"title": "Not Found",
"detail": "The related resource does not exist.",
"source": {
      "pointer": "/data"
}

Conclusion: This feels like a topic that a lot of potential users might have trouble with. Going through the documentation, sadly, I was unable to find any related topics for such a question. Going by the response received from the server, it is rather unclear as to what might be the solution. Thank you.

lindyhopchris commented 5 years ago

Hi!

You request doesn't comply with the JSON API spec. For a POST request to a has-many relationship endpoint, the spec says:

For all request types, the body MUST contain a data member whose value is an empty array or an array of resource identifier objects.

If a client makes a POST request to a URL from a relationship link, the server MUST add the specified members to the relationship unless they are already present. https://jsonapi.org/format/#crud-updating-to-many-relationships

I.e. the employee must already exist for the resource identifier to be valid and it to be added to the stores employees' relationship.

Your request should actually be:

POST /api/employees HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "employees",
    "attributes": {
      "name":"mr freeman",
      "position":"sales manager",
    },
    "relationships": {
      "store": {
        "data": {
          "type": "stores",
          "id": "1"
        }
      }
    }
  }
}

Your question does reveal a bug in this package though - the package should actually be replying with something like this response:

HTTP/1.1 400 Bad Response
Content-Type: application/vnd.api+json

{
   "errors":[
      {
         "status":"400",
         "title":"Bad Request",
         "detail":"Relationship endpoints must receive relationship identifier objects.",
         "source":{
            "pointer":"/data"
         }
      }
   ]
}
karlis-simanovics commented 5 years ago

Greetings! Thank you for the explanation, seems like my fault for overlooking important points in the JSON:API documentation.

I assume that Your 'request" example was pointing out the absence of headers in the examples I posted. I didn't include the necessary headers in my examples, since that did not seem to be the origin of the issue posted, but I can confirm that the headers I use definitely match the ones You posted in the example. Besides that, I'm assuming the /api/employees requests compared are completely identical.

lindyhopchris commented 5 years ago

Ah sorry, it's not the absence of headers that's important, it's that it must be sent to POST /api/employees

lindyhopchris commented 5 years ago

The package now rejects resource objects that are sent in relationships, via f9e00f1a0a4d5864495d22f881484e5f0c25d3c2