marshmallow-code / marshmallow-jsonapi

JSON API 1.0 (https://jsonapi.org/) formatting with marshmallow
https://marshmallow-jsonapi.readthedocs.io
MIT License
216 stars 67 forks source link

How to add meta tag to a resource identifier object in relationship ? #255

Open goutamenara opened 5 years ago

goutamenara commented 5 years ago

How to add meta tag to a resource identifier in a relationship as shown in the example below

Example {json:api} data : { "data" : { "type" : "products", "id" : "1", "relationships" : { "processes" : { "data" : [ { "type" : "processes", "id" : "15", "meta" : { "order" : "1" } } ] } } } }

multimeric commented 5 years ago

Refer to the documentation here: https://marshmallow-jsonapi.readthedocs.io/en/latest/quickstart.html#meta-information.

Broadly, you use the marshmallow_jsonapi.fields.DocumentMeta() field in your schema.

multimeric commented 5 years ago

Although having said that, if order refers to another resource, you should be treating the order number as a relationship and not as meta information. In this case you would use the marshmallow_jsonapi.fields.Relationship() field.

goutamenara commented 5 years ago

@TMiguelT Thanks for the reply,

marshmallow_jsonapi.fields.DocumentMeta()adds meta data to the top level document. I wish to add meta data to resource identifier object . In the example given processes represents a To-Many Relationship and order represents just a number to identify the sequence of the processes.

json api specification allows adding meta information in resource identifier objects

A “resource identifier object” MAY also include a meta member, whose value is a meta object that contains non-standard meta-information.

The documentation defines two types of meta information marshmallow_jsonapi.fields.DocumentMeta() for document level and marshmallow_jsonapi.fields.ResourceMeta() for resource level can any of this can be used to add meta information to resource identifier object.

multimeric commented 5 years ago

Ah sorry I didn't parse the JSON structure properly. Here's a formatted version:

{
  "data": {
    "type": "products",
    "id": "1",
    "relationships": {
      "processes": {
        "data": [
          {
            "type": "processes",
            "id": "15",
            "meta": {
              "order": "1"
            }
          }
        ]
      }
    }
  }
}
multimeric commented 5 years ago

In any case, I believe you are right that this is a bug.

Here's a simple test case derived from your example:

https://gist.github.com/TMiguelT/932ae76b71c5cea79f45937b92a5ebe8

from marshmallow_jsonapi import fields, Schema
import json

class ProductSchema(Schema):
    class Meta:
        type_ = "products"

    id = fields.String()
    processes = fields.Relationship(
        type_="processes",
        id_field="id",
        include_resource_linkage=True,
        schema="ProcessSchema",
        many=True
    )

class ProcessSchema(Schema):
    class Meta:
        type_ = "processes"

    id = fields.String()
    meta = fields.ResourceMeta()
    some_field = fields.String()

serialized = ProductSchema().dump({
    "id": "1",
    "processes": [
        {
            "id": 15,
            "some_field": 123,
            "meta": {
                "order": "1"
            }
        }
    ]
})

print(json.dumps(serialized, indent=4))

# This assertion fails
assert 'meta' in serialized['data']['relationships']['processes']['data'][0]

Basically, I'm asserting that the associated processes have a meta field, when we set include_resource_linkage=True, and this is not the case. Instead, it prints:

{
    "data": {
        "type": "products",
        "id": "1",
        "relationships": {
            "processes": {
                "data": [
                    {
                        "type": "processes",
                        "id": "15"
                    }
                ]
            }
        }
    }
}

The source of the issue is here, where we only ever use id and type when creating a linkage object: https://github.com/marshmallow-code/marshmallow-jsonapi/blob/7d6b8236bd39ab362b7c674591d4ead90838e3d8/marshmallow_jsonapi/fields.py#L173-L184

multimeric commented 5 years ago

However, while this is a bug, I would be surprised if your order number needs to be a meta field, as I said. It sounds like it should be a relationship on processes.

goutamenara commented 5 years ago

However, while this is a bug, I would be surprised if your order number needs to be a meta field, as I said. It sounds like it should be a relationship on processes.

In my case processes is a general collection containing all the processes, and for a product there will be 3 or 4 processes as a relationship in a specific order. For the same process , order can be different for different products. For example for product1 , process1 comes first and may be for product2 , process1 can come as a 3rd process.

That's why i thought adding a meta information to resource link will help me identify the order of process.

multimeric commented 5 years ago

Oh, I see. It's "order" in the sense of the position in a list. I thought you meant order in the sense of "purchase". In that case I agree with you, that sounds like it could reasonably be a meta property, since it's not technically a field.

On the other hand, the JSON API spec does say:

Note: The spec does not impart meaning to order of resource identifier objects in linkage arrays of to-many relationships, although implementations may do that. Arrays of resource identifier objects may represent ordered or unordered relationships, and both types can be mixed in one response object.

So, if you want, you could hack the Relationship field in order to ensure that the processes are in sorted order. That wouldn't violate the spec. But that would also be tricky using this library.