How to handle multiple endpoints/links

How would you notify the user about the multiple links/endpoints on the “homepage” of the api or in any other endpoint where there are multiple options/links?
Would you do that like this?

{
  "links": {
    "self": "http://example.com/",
  },
  "data": [{
    "relationships": {
      "articles": {
        "links": {
          "self": "http://example.com/articles",
        },
      },
      "authors": {
        "links": {
          "self": "http://example.com/authors",
        },
      },
      "brands": {
        "links": {
          "self": "http://example.com/brands",
        },
      },
      "search": {
        "links": {
          "self": "http://example.com/articles/search/{keyword}",
        },
      }
    },
  }]
}

Thanks in advance!

JSON API doesn’t yet define a standard way to do this (though there’s an issue for it), so you’re allowed to return any compliant JSON API response. Something like what you proposed makes a lot of sense, but it has a couple small incompatibilities with the specification. Below’s a tweaked version that would be valid:

{
  "links": {
    "self": "http://example.com/",
  },
  // Below, I used an object for data rather than an array,
  // since that seemed simpler, but either is valid.
  "data": {
    // the type and id values here can be whatever you'd like,
    // but JSON API requires every resource provide something.
    "type": "entrypoint",
    "id": "1",
    "relationships": {
      "articles": {
        "links": {
          "self": "http://example.com/articles",
        }
      },
      "authors": {
        "links": {
          "self": "http://example.com/authors",
        }
      },
      "brands": {
        "links": {
          "self": "http://example.com/brands",
        }
      },
      "search": {
        // Templated links aren't defined in the base spec,
        // but you can put them in `meta`.
        "meta": {
          "uri-template": "http://example.com/articles/search/{keyword}"
        }
      }
    }
  }
}

Hello @ethanresnick and @Sephen, I am trying to solve the same issue of providing templated links in a JSONAPI response. I have few follow-up questions/comments based on your discussion here.

  1. In the example provided by @ethanresnick, it says this:
    // Templated links aren't defined in the base spec,
    // but you can put them in `meta`.

Does the spec actually prohibit URI templates as URL values in links objects?

I can think of one problem with including URI templates, which is that clients may not (and likely will not) expect to receive templated URIs as links and therefore may try to fetch them directly, missing the needed interpolation of the template.
On the other hand, I don’t see which part of the spec makes templated URIs as links invalid, so is it truly non-compliant to include them?

I find it somewhat more appealing to provide a URI template in the link rather than in the meta field, although I’d like to remain spec-compliant if possible.

  1. @Sephen if you are willing to share, I’m curious what solution you ended up using for this issue.

  2. It looks like there’s a needed correction to the key names within the relationshop objects’ links in the example (self → related).

Reading JSON:API — Latest Specification (v1.1), I see the following descriptions:

“self: a link for the relationship itself (a “relationship link”).”
“related: a related resource link”

Further, related resource link is defined as

A “related resource link” provides access to [resource objects] linked in a relationship. When fetched, the related resource object(s) are returned as the response’s primary data.

Decoding that for the example below, it seems like the links to the actual “articles,” “authors,” and “brands” resource objects should be the related links, not the self links.

Below I’ve updated the @ethanresnick’s example to change the “self” to “related” and also added the valid “self” links to be explicit.

{
  "links": {
    "self": "http://example.com/",
  },
  // Below, I used an object for data rather than an array,
  // since that seemed simpler, but either is valid.
  "data": {
    // the type and id values here can be whatever you'd like,
    // but JSON API requires every resource provide something.
    "type": "entrypoint",
    "id": "1",
    "relationships": {
      "articles": {
        "links": {
          // by the spec we are not obligated to have both "self" and "related"
          // but i'm including them to show the difference
          // reference: http://jsonapi.org/format/#document-resource-object-relationships
          "self": "http://example.com/entrypoint/relationships/articles",
          "related": "http://example.com/articles",
        }
      },
      "authors": {
        "links": {
          // it might be more consistent to not have "entrypoint/" in this URL
          // and do this instead:
          // "self": "http://example.com/relationships/authors",
          // but either way should be valid
          "self": "http://example.com/entrypoint/relationships/authors",
          "related": "http://example.com/authors",
        }
      },
      "brands": {
        "links": {
          "self": "http://example.com/entrypoint/relationships/brands",
          "related": "http://example.com/brands",
        }
      },
      "search": {
        // Templated links aren't defined in the base spec,
        // but you can put them in `meta`.
        "meta": {
          "uri-template": "http://example.com/articles/search/{keyword}"
        }
      }
    }
  }
}

Hi @skarger,

For now i abandoned the templated links and am using the JSONAPI filter parameter method. I wasn’t able to come up with something which i was happy with, so i’m just going to cover this in the api documentation which IMO is better than trying to put all “documentation” in the api itself.

1 Like

Hey @skarger! Thanks for fixing my example!

To your questions…

Yup, this is exactly the issue.

The links section says that the value/href must be a URL. Now, a template is technically a URI, and could be a URL if you put something up at the template’s page, but I think that would go against what the spec is trying to imply.

More concretely, there are lines throughout the spec like: “A server MUST respond to a GET request to the specified URL with a response that includes the resource as the primary data.” (from the section on resource links). That seems to say pretty clearly that the URL as given (i.e. without any template expansion) must be dereference to an appropriate result.

Going forward, both you and @Sephen may want to keep an eye on profile extensions, which will make it possible to annotate templated links in meta with a reference to an external specification, so that generic clients can understand the meaning of those links.

1 Like