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

Full JSON-API support #1235

Open
11 tasks done
joaomdmoura opened this issue Oct 5, 2015 · 15 comments
Open
11 tasks done

Full JSON-API support #1235

joaomdmoura opened this issue Oct 5, 2015 · 15 comments

Comments

@joaomdmoura
Copy link
Member

tl;dr

We need to cover what we are missing, mostly the links (all-levels)


Right now we are covering most of JSON-API conventions but there are some tiny parts missing and we need sync this up.
We are really missing all-levels links support, right now I think there might be just one missing, but we also need to double check overall convention to make sure we are good to go.


related to issues:

related to PRs:

@tommyblue
Copy link

Hi @joaomdmoura, is it possible with 0.10.0.rc3 to use links? I tried with:

render json: @categories, links: { "self": "http://example.com/api/posts" }, each_serializer: Api::V1::CategorySerializer

but I only have the "data" key in the JSON object :/

@beauby
Copy link
Contributor

beauby commented Oct 6, 2015

@tommyblue Could you try #1247?

@tommyblue
Copy link

it's ok!
I'd like to find a good way to automatically add at least the self link.
Something like this: links: { self: { href: request.url } }
Probably it could be automatically added if set using a config variable

@bf4
Copy link
Member

bf4 commented Oct 7, 2015

The adapter has access to the request object (as context)

@bf4
Copy link
Member

bf4 commented Oct 7, 2015

@joaomdmoura I'd like to break up the errors rfc into 1) the mvp error objects 2) all error objects 3) decide if we require an errors key or an ActiveModel::Errors or something that responds to errors 4) to what extent error codes and status codes live in AMS

@joaomdmoura
Copy link
Member Author

@bf4 👍 thx for update the issue.
What exactly do you mean by break up? different issues / PRs? check boxes?
Let's keep the focus on MVP

@tchak
Copy link
Contributor

tchak commented Oct 20, 2015

It seems relationship-level links and meta are missing from the checklist

@tchak
Copy link
Contributor

tchak commented Oct 20, 2015

Relationship-level pagination links are also not supported right now I belive

@beauby
Copy link
Contributor

beauby commented Oct 20, 2015

@tchak Very true, I edited the checklist. Thanks!

@tchak
Copy link
Contributor

tchak commented Oct 20, 2015

@beauby I found a pull request you can link to #1028

@bf4
Copy link
Member

bf4 commented Oct 20, 2015

@rails-api/ams per http://jsonapi.org/schema pasted below we can break our goals up into

would make a nice roadmap

  • success
    • data: "$ref": "#/definitions/data"
    • included: array of unique items of type "$ref": "#/definitions/resource"
    • meta: "$ref": "#/definitions/meta"
    • links:
      • link: "$ref": "#/definitions/links"
      • pagination: "$ref": "#/definitions/pagination"
    • jsonapi: "$ref": "#/definitions/jsonapi"
  • failure
    • errors: array of unique items of type "$ref": "#/definitions/error"
    • meta: "$ref": "#/definitions/meta"
    • jsonapi: "$ref": "#/definitions/jsonapi"
  • info
    • meta: "$ref": "#/definitions/meta"
    • links: "$ref": "#/definitions/links"
    • jsonapi: "$ref": "#/definitions/jsonapi"
  • definitions:
    • meta
    • data: oneOf (resource, array of unique resources)
    • resource
      • attributes
      • relationships
        • relationshipToOne
          • empty
          • linkage
            • meta
        • relationshipToMany
          • linkage
            • meta
      • links
      • meta
    • links
      • link
        • uri
        • href, meta
    • pagination
    • jsonapi
      • meta
    • error: id, links, status, code, title: detail: source [{pointer, type}, {parameter: {description, type}], meta
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "JSON API Schema",
  "description": "This is a schema for responses in the JSON API format. For more, see http://jsonapi.org",
  "oneOf": [
    {
      "$ref": "#/definitions/success"
    },
    {
      "$ref": "#/definitions/failure"
    },
    {
      "$ref": "#/definitions/info"
    }
  ],

  "definitions": {
    "success": {
      "type": "object",
      "required": [
        "data"
      ],
      "properties": {
        "data": {
          "$ref": "#/definitions/data"
        },
        "included": {
          "description": "To reduce the number of HTTP requests, servers **MAY** allow responses that include related resources along with the requested primary resources. Such responses are called \"compound documents\".",
          "type": "array",
          "items": {
            "$ref": "#/definitions/resource"
          },
          "uniqueItems": true
        },
        "meta": {
          "$ref": "#/definitions/meta"
        },
        "links": {
          "description": "Link members related to the primary data.",
          "allOf": [
            {
              "$ref": "#/definitions/links"
            },
            {
              "$ref": "#/definitions/pagination"
            }
          ]
        },
        "jsonapi": {
          "$ref": "#/definitions/jsonapi"
        }
      },
      "additionalProperties": false
    },
    "failure": {
      "type": "object",
      "required": [
        "errors"
      ],
      "properties": {
        "errors": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/error"
          },
          "uniqueItems": true
        },
        "meta": {
          "$ref": "#/definitions/meta"
        },
        "jsonapi": {
          "$ref": "#/definitions/jsonapi"
        }
      },
      "additionalProperties": false
    },
    "info": {
      "type": "object",
      "required": [
        "meta"
      ],
      "properties": {
        "meta": {
          "$ref": "#/definitions/meta"
        },
        "links": {
          "$ref": "#/definitions/links"
        },
        "jsonapi": {
          "$ref": "#/definitions/jsonapi"
        }
      },
      "additionalProperties": false
    },

    "meta": {
      "description": "Non-standard meta-information that can not be represented as an attribute or relationship.",
      "type": "object",
      "additionalProperties": true
    },
    "data": {
      "description": "The document's \"primary data\" is a representation of the resource or collection of resources targeted by a request.",
      "oneOf": [
        {
          "$ref": "#/definitions/resource"
        },
        {
          "description": "An array of resource objects, an array of resource identifier objects, or an empty array ([]), for requests that target resource collections.",
          "type": "array",
          "items": {
            "$ref": "#/definitions/resource"
          },
          "uniqueItems": true
        }
      ]
    },
    "resource": {
      "description": "\"Resource objects\" appear in a JSON API document to represent resources.",
      "type": "object",
      "required": [
        "type",
        "id"
      ],
      "properties": {
        "type": {
          "type": "string"
        },
        "id": {
          "type": "string"
        },
        "attributes": {
          "$ref": "#/definitions/attributes"
        },
        "relationships": {
          "$ref": "#/definitions/relationships"
        },
        "links": {
          "$ref": "#/definitions/links"
        },
        "meta": {
          "$ref": "#/definitions/meta"
        }
      },
      "additionalProperties": false
    },

    "links": {
      "description": "A resource object **MAY** contain references to other resource objects (\"relationships\"). Relationships may be to-one or to-many. Relationships can be specified by including a member in a resource's links object.",
      "type": "object",
      "properties": {
        "self": {
          "description": "A `self` member, whose value is a URL for the relationship itself (a \"relationship URL\"). This URL allows the client to directly manipulate the relationship. For example, it would allow a client to remove an `author` from an `article` without deleting the people resource itself.",
          "type": "string",
          "format": "uri"
        },
        "related": {
          "$ref": "#/definitions/link"
        }
      },
      "additionalProperties": true
    },
    "link": {
      "description": "A link **MUST** be represented as either: a string containing the link's URL or a link object.",
      "oneOf": [
        {
          "description": "A string containing the link's URL.",
          "type": "string",
          "format": "uri"
        },
        {
          "type": "object",
          "required": [
            "href"
          ],
          "properties": {
            "href": {
              "description": "A string containing the link's URL.",
              "type": "string",
              "format": "uri"
            },
            "meta": {
              "$ref": "#/definitions/meta"
            }
          }
        }
      ]
    },

    "attributes": {
      "description": "Members of the attributes object (\"attributes\") represent information about the resource object in which it's defined.",
      "type": "object",
      "patternProperties": {
        "^(?!relationships$|links$)\\w[-\\w_]*$": {
          "description": "Attributes may contain any valid JSON value."
        }
      },
      "additionalProperties": false
    },

    "relationships": {
      "description": "Members of the relationships object (\"relationships\") represent references from the resource object in which it's defined to other resource objects.",
      "type": "object",
      "patternProperties": {
        "^\\w[-\\w_]*$": {
          "properties": {
            "links": {
              "$ref": "#/definitions/links"
            },
            "data": {
              "description": "Member, whose value represents \"resource linkage\".",
              "oneOf": [
                {
                  "$ref": "#/definitions/relationshipToOne"
                },
                {
                  "$ref": "#/definitions/relationshipToMany"
                }
              ]
            },
            "meta": {
              "$ref": "#/definitions/meta"
            }
          },
          "additionalProperties": false
        }
      },
      "additionalProperties": false
    },
    "relationshipToOne": {
      "description": "References to other resource objects in a to-one (\"relationship\"). Relationships can be specified by including a member in a resource's links object.",
      "anyOf": [
        {
          "$ref": "#/definitions/empty"
        },
        {
          "$ref": "#/definitions/linkage"
        }
      ]
    },
    "relationshipToMany": {
      "description": "An array of objects each containing \"type\" and \"id\" members for to-many relationships.",
      "type": "array",
      "items": {
        "$ref": "#/definitions/linkage"
      },
      "uniqueItems": true
    },
    "empty": {
      "description": "Describes an empty to-one relationship.",
      "type": "null"
    },
    "linkage": {
      "description": "The \"type\" and \"id\" to non-empty members.",
      "type": "object",
      "required": [
        "type",
        "id"
      ],
      "properties": {
        "type": {
          "type": "string"
        },
        "id": {
          "type": "string"
        },
        "meta": {
          "$ref": "#/definitions/meta"
        }
      },
      "additionalProperties": false
    },
    "pagination": {
      "type": "object",
      "properties": {
        "first": {
          "description": "The first page of data",
          "oneOf": [
            { "type": "string", "format": "uri" },
            { "type": "null" }
          ]
        },
        "last": {
          "description": "The last page of data",
          "oneOf": [
            { "type": "string", "format": "uri" },
            { "type": "null" }
          ]
        },
        "prev": {
          "description": "The previous page of data",
          "oneOf": [
            { "type": "string", "format": "uri" },
            { "type": "null" }
          ]
        },
        "next": {
          "description": "The next page of data",
          "oneOf": [
            { "type": "string", "format": "uri" },
            { "type": "null" }
          ]
        }
      }
    },

    "jsonapi": {
      "description": "An object describing the server's implementation",
      "type": "object",
      "properties": {
        "version": {
          "type": "string"
        },
        "meta": {
          "$ref": "#/definitions/meta"
        }
      },
      "additionalProperties": false
    },

    "error": {
      "type": "object",
      "properties": {
        "id": {
          "description": "A unique identifier for this particular occurrence of the problem.",
          "type": "string"
        },
        "links": {
          "$ref": "#/definitions/links"
        },
        "status": {
          "description": "The HTTP status code applicable to this problem, expressed as a string value.",
          "type": "string"
        },
        "code": {
          "description": "An application-specific error code, expressed as a string value.",
          "type": "string"
        },
        "title": {
          "description": "A short, human-readable summary of the problem. It **SHOULD NOT** change from occurrence to occurrence of the problem, except for purposes of localization.",
          "type": "string"
        },
        "detail": {
          "description": "A human-readable explanation specific to this occurrence of the problem.",
          "type": "string"
        },
        "source": {
          "type": "object",
          "properties": {
            "pointer": {
              "description": "A JSON Pointer [RFC6901] to the associated entity in the request document [e.g. \"/data\" for a primary data object, or \"/data/attributes/title\" for a specific attribute].",
              "type": "string"
            },
            "parameter": {
              "description": "A string indicating which query parameter caused the error.",
              "type": "string"
            }
          }
        },
        "meta": {
          "$ref": "#/definitions/meta"
        }
      },
      "additionalProperties": false
    }
  }
}

@gaganawhad
Copy link

@joaomdmoura Thanks for all the work here.

Do you know of a workaround for Resource-level meta object that I can use for the time-being ?

@gaganawhad
Copy link

@joaomdmoura I would be happy to try submitting a PR For Resource-level meta. Does that work? Any reason not to ? Let me know! Thanks.

@beauby
Copy link
Contributor

beauby commented Nov 13, 2015

@gaganawhad Adding resource-level meta should be fairly easy. I wanted to do it after the resource-level links but got busy with other stuff. So feel free to make one, and ask questions on Slack if need be. I'll be happy to review it.

@beauby
Copy link
Contributor

beauby commented Jan 21, 2016

ref #1454

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

No branches or pull requests

6 participants