Skip to content

Default to JSON and HAL#3

Open
tomyan wants to merge 2 commits into
masterfrom
media-types-and-hal
Open

Default to JSON and HAL#3
tomyan wants to merge 2 commits into
masterfrom
media-types-and-hal

Conversation

@tomyan
Copy link
Copy Markdown

@tomyan tomyan commented Aug 25, 2020

Split out guidance for response media types and recommend HAL

Split out guidance for response media types and recommend HAL
Comment thread README.md Outdated

The JSON should follow the [JSON HAL (Hypertext Application Language)](https://tools.ietf.org/html/draft-kelly-json-hal-08) specification.

In order to make the API consumable by any client that understands JSON and not require a HAL capable client, the `Content-Type` of the response should be `application/hal+json` only if the client sends that media type in the `Accept` request header. Otherwise the same content should be returned with `Content-Type: application/json`. Furthermore advanced HAL features like templated links should be avoided.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to explain why templated links should be avoided.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have added. Do you agree, or do you think we should embrace all of HAL?

@aceakash
Copy link
Copy Markdown

Apart from pagination, what's the use case for using that HAL specification?

We generally don't link to other resources arbitrarily (what would go in _links), but rather capture the relationship as an attribute of the primary resource.

e.g. in an intel, the linked companies are captured in the document itself:

{
    intel: [
        {
            headline: "blah",
            ..
            ..
            companyRelationships: {
                bidders: [
                    {
                        id: "prime-123",
                        name: "HSBC plc",
                        url: "https://company-store.mmgapi.net/prime-123"
                    }
                ],
                targets: [
                    {
                        id: "prime-789",
                        name: "Monzo plc",
                        url: "https://company-store.mmgapi.net/prime-789"
                    }
                ]
            },
        }
    ]
}

Note the url (naming up for grabs) field in the company object itself, which allows clients to navigate to the canonical version of that sub-resource.

Keeping links closer to the linked object itself is better than having it in a top level _links, in my opinion.

@tomyan
Copy link
Copy Markdown
Author

tomyan commented Aug 26, 2020

I think it's to have a standardised way to link and embed resources. Your example might be expressed as:

{
  "headline": "blah",
  "_links": {
    "bidders": [
      { "href": "https://company-store.mmgapi.net/prime-123" }
    ],
    "targets": [
      { "href": "https://company-store.mmgapi.net/prime-456" }
    ]
  }
}

It seems to favour shallow linking or full embedding of related resources, rather than the perhaps more intuitive nesting of parts of embedded resources as you had it.

The things that drew me to it were:

  • I'd like to see us primarily use hyperlinking to link resources to make APIs more discoverable, rather than using IDs and relying on knowledge of what API endpoints expect those IDs. Your example does link so not an issue there, but we have plenty where we don't.
  • It's an existing standard we could use rather than creating our own conventions.

I do think what you gain in standardisation you perhaps lose in how intuitive the response structure feels, so perhaps we should just define our own conventions?

@aceakash
Copy link
Copy Markdown

Unless the "standard" gives us a lot of benefits, such as readily-available tooling, I think we should borrow the good parts from it and incorporate into what we already have.

The architecture we've widely adopted is to model resources as de-normalised documents, with other embedded and linked resources represented as relationships. This maps nicely when you unmarshal into a domain object in your code that you can just use.

The API is a conduit to serving resources - if the resource structure is already well-defined, the API shouldn't then deconstruct that resource. We'll likely be exposing the resource via other channels, like AMQP or SNS, and the resource coming through there should be the same as the resource exposed here. The only thing that should differ is the envelope.

Maybe the _links section might be better served for exposing other API endpoints, rather than extract relationships from the resource itself.

e.g.

{
    _links: {
        self: "/intelligence?after=59342765283465",
        next: "/intelligence?after=22342342342342",
        index: "/intelligence",
        workflowActions: {
            href: "/intelligence/actions",
            method: "POST"
        },
        docs: "https://github.com/my-api/docs.md"
    },
    results: [
        {
            ... full intel ...
        },
        {
            ... full intel ...
        }
    ]
}

@ivoreis
Copy link
Copy Markdown

ivoreis commented Aug 26, 2020

From my POV both options have pros and cons and it depends on what are we trying to optimize towards.

Having a de-normalised API response is useful to get all the data back you need (and data you don't) with a minimum number of requests but hard to have good access control of what data should/need to be exposed.

On the other hand, having a normalized API will help understand (provide insights) what data is used/needed and we have more fine-grain control about who should access that specific resource. (downside is more requests, more changes to hit rate limiting)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants