jsonapi-rb / jsonapi-renderer

Efficiently render JSON API documents.
http://jsonapi-rb.org
MIT License
27 stars 11 forks source link

Relationships object does not render if fields are restricted in main resource #19

Closed hectorsq closed 7 years ago

hectorsq commented 7 years ago

Given the following resources:

class SerializableInvoice < JSONAPI::Serializable::Resource
  type 'invoices'
  attribute :series
  attribute :number
  attribute :issue_date
  attribute :status
  attribute :total
  has_one :company
  has_many :invoice_items
end

class SerializableInvoiceItem < JSONAPI::Serializable::Resource
  type 'invoice_items'
  attribute :quantity
  attribute :description
  attribute :unit_price
  attribute :total
end

class SerializableCompany < JSONAPI::Serializable::Resource
  type 'companies'
  attribute :name
  attribute :tax_code
  attribute :street
  attribute :zip_code
end

When I render in Rails using the following code (notice the commented lines)

    include = params[:include]
    render jsonapi: @invoices,
      include: include,
      fields: {
        # invoices: [:series, :number],
        # companies: [:name, :zip_code],
        # invoice_items: [:description]
      }

I get the following JSON, where everything is fine:

// 20170611003659
// http://localhost:3000/api/invoices?series=B&number=45&include=invoice_items,company

{
  "data": [
    {
      "id": "3563",
      "type": "invoices",
      "attributes": {
        "series": "B",
        "number": 45,
        "issue_date": "2017-04-19",
        "status": "PENDING",
        "total": "70992.0"
      },
      "relationships": {
        "company": {
          "data": {
            "type": "companies",
            "id": "29"
          }
        },
        "invoice_items": {
          "data": [
            {
              "type": "invoice_items",
              "id": "1096"
            }
          ]
        }
      }
    }
  ],
  "included": [
    {
      "id": "29",
      "type": "companies",
      "attributes": {
        "name": "Ferrocarril y Terminal del Valle de México, S.A. de C.V.",
        "tax_code": "FTV961129GP7",
        "street": "Av. Mario Colín",
        "zip_code": "54150"
      }
    },
    {
      "id": "1096",
      "type": "invoice_items",
      "attributes": {
        "quantity": "1.0",
        "description": "Soporte a sistema SD, SLS, PreFacturación, SLI macros, Carhire. Trimestre 2017-2. OL3 35568 31/01/17",
        "unit_price": "61200.0",
        "total": "61200.0"
      }
    }
  ]
}

If I filter some fields from the included resources:

    include = params[:include]
    render jsonapi: @invoices,
      include: include,
      fields: {
        # invoices: [:series, :number],
        companies: [:name, :zip_code],
        invoice_items: [:description]
      }

I get the expected JSON:

// 20170611004045
// http://localhost:3000/api/invoices?series=B&number=45&include=invoice_items,company

{
  "data": [
    {
      "id": "3563",
      "type": "invoices",
      "attributes": {
        "series": "B",
        "number": 45,
        "issue_date": "2017-04-19",
        "status": "PENDING",
        "total": "70992.0"
      },
      "relationships": {
        "company": {
          "data": {
            "type": "companies",
            "id": "29"
          }
        },
        "invoice_items": {
          "data": [
            {
              "type": "invoice_items",
              "id": "1096"
            }
          ]
        }
      }
    }
  ],
  "included": [
    {
      "id": "29",
      "type": "companies",
      "attributes": {
        "name": "Ferrocarril y Terminal del Valle de México, S.A. de C.V.",
        "zip_code": "54150"
      }
    },
    {
      "id": "1096",
      "type": "invoice_items",
      "attributes": {
        "description": "Soporte a sistema SD, SLS, PreFacturación, SLI macros, Carhire. Trimestre 2017-2. OL3 35568 31/01/17"
      }
    }
  ]
}

However if I filter some fields from the main resource:

    include = params[:include]
    render jsonapi: @invoices,
      include: include,
      fields: {
        invoices: [:series, :number],
        companies: [:name, :zip_code],
        invoice_items: [:description]
      }

The relationships object is not rendered

// 20170611004137
// http://localhost:3000/api/invoices?series=B&number=45&include=invoice_items,company

{
  "data": [
    {
      "id": "3563",
      "type": "invoices",
      "attributes": {
        "series": "B",
        "number": 45
      }
    }
  ],
  "included": [
    {
      "id": "29",
      "type": "companies",
      "attributes": {
        "name": "Ferrocarril y Terminal del Valle de México, S.A. de C.V.",
        "zip_code": "54150"
      }
    },
    {
      "id": "1096",
      "type": "invoice_items",
      "attributes": {
        "description": "Soporte a sistema SD, SLS, PreFacturación, SLI macros, Carhire. Trimestre 2017-2. OL3 35568 31/01/17"
      }
    }
  ]
}

I've found that adding the relationships in the fields hash fixes it

    include = params[:include]
    render jsonapi: @invoices,
      include: include,
      fields: {
        invoices: [:series, :number, :company, :invoice_items],
        companies: [:name, :zip_code],
        invoice_items: [:description]
      }

Rendering the expected JSON:

// 20170611135556
// http://localhost:3000/api/invoices?series=B&number=45&include=invoice_items,company

{
  "data": [
    {
      "id": "3563",
      "type": "invoices",
      "attributes": {
        "series": "B",
        "number": 45
      },
      "relationships": {
        "company": {
          "data": {
            "type": "companies",
            "id": "29"
          }
        },
        "invoice_items": {
          "data": [
            {
              "type": "invoice_items",
              "id": "1096"
            }
          ]
        }
      }
    }
  ],
  "included": [
    {
      "id": "29",
      "type": "companies",
      "attributes": {
        "name": "Ferrocarril y Terminal del Valle de México, S.A. de C.V.",
        "zip_code": "54150"
      }
    },
    {
      "id": "1096",
      "type": "invoice_items",
      "attributes": {
        "description": "Soporte a sistema SD, SLS, PreFacturación, SLI macros, Carhire. Trimestre 2017-2. OL3 35568 31/01/17"
      }
    }
  ]
}

Is this a bug or is this the expected behavior?

beauby commented 7 years ago

This is expected behavior as fields refers to the union of attributes and relationships. The fact that the relationships member is not rendered in your example is simply a consequence of all relationships being filtered out.