Content type of links

Are there any recommended strategies for specifying the content type of links? E.g. suppose that in addition to the JSON representation of the resource pointed to by links.self, there are HTML and PDF versions of the resource.

In general you’d want your JSON, HTML and PDF to all reside at the same location (self link), and for the requested Content-Type to be discriminating factor, but

  • a) how do you document that the alternative formats are available if you only include a single self, and
  • b) what if the other representations don’t actually reside at the same address?
{
  ...
  "id": 1,
  "links": {
    "self": "https://api.com/resources/1",
    "pdf": "https://api.com/resources/obfuscated-pdf-url",
    ...
  }
}

^ Is all I can think of.

After diving into this forum over the past week or so, it looks like links with arbitrary names aren’t supported; only the link names from the specification are allowed.

Something like this might be more in keeping with the spec, keeping in mind that content negotiation is the way to request specific formats:

{
  ...
  "id": 1,
  "links": {
    "self": "https://api.com/resources/1",
    "meta": {
      "content_types": [
        "application/pdf",
        ...
      ]
    }
  }
}

FWIW, I would add the Content-Type within the specific links’ metadata. Ex:

{
  "id": "1",
  "links": {
    "self": "https://api.com/resources/1",
    "pdf": {
      "href": "https://api.com/resources/obfuscated-pdf-url",
      "meta": {
        "contentType": "application/pdf"
      }
    }
  }
}

OR, if the different Content-Types are at the same URL;

{
  "id": "1",
  "links": {
    "self": {
      "href": "https://api.com/resources/1",
      "meta": {
        "contentTypes": [
          "application/vnd.api+json",
          "application/pdf"
        ]
      }
    }
  }
}

You’re right about using a link object with href and meta properties! Good catch.

1 Like

I don’t think this is valid JSON:API.

The Content-Type header must be application/vnd.api+json.

To provide assets like PDFs, this should be in its own API. For example, api.example.com is a JSON:API service and may give links to PDFs that can be retrieved through static.example.com.

It’s a similar issue to developers trying all sorts of things to handle authentication with JSON:API while session keys can simply be returned through another API like auth.example.com that follows whatever format makes sense.

It’s not clear that other content types should not be available and negotiable at all. The “Content Negotiation” section specifies how the application/vnd.api+json should be unqualified, but does not require that all requests and responses have that media type.

Given how often the specification emphasizes that HTTP semantics should be followed, it would be surprising if the intent is to prevent content negotiation or to require that binary content is only available at a separate service name.

It would be nice if the spec were more clear on this matter, though.

Sure, a request for a PDF wouldn’t be a JSON:API request, but it would be nice to reference the URL somewhere in the resource document. Perhaps in the resource meta object instead @maark?

{
  "id": "1",
  "links": {
    "self": "https://api.com/resources/1"
  },
  "meta": {
    "pdf": "https://api.com/resources/obfuscated-pdf-url"
  }
}

When dealing with multiple representations of a resource in different formats (such as JSON, HTML, and PDF), there are a few strategies you can use to specify the content type of links. Here are some recommendations:

1. Use the Accept Header:

  • Clients can specify the desired content type using the Accept header in their HTTP request. The server can then respond with the appropriate representation based on the client’s preference.
  • Example:

httpCopy code

GET /resources/1
Accept: application/json

2. Multiple self Links with Different Content Types:

  • Include multiple self links in your response, each pointing to a different representation of the resource.
  • Example:

jsonCopy code

{
  "id": 1,
  "links": {
    "self": "https://api.com/resources/1",
    "json": "https://api.com/resources/1.json",
    "html": "https://api.com/resources/1.html",
    "pdf": "https://api.com/resources/1.pdf"
  }
}

Please note that this violates the JSON:API specification. Implementations are not allowed to add new members to the links object defined by the specification.

I create a tool for online json validation or testing please check the tool and give me feed back.

Hello,
In my opinion, To specify content types for links, use the Link header in HTTP responses and an alternate links array in your JSON:

{
  "id": 1,
  "links": {
    "self": "https://api.com/resources/1",
    "alternate": [
      { "href": "https://api.com/resources/1", "type": "text/html" },
      { "href": "https://api.com/resources/obfuscated-pdf-url", "type": "application/pdf" }
    ]
  }
}

This is well-described in the 1.1 spec: JSON:API — Latest Specification (v1.1)