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

media type for request with existing vendor tree #1020

Closed
bf4 opened this Issue Apr 4, 2016 · 6 comments

Comments

Projects
None yet
2 participants
@bf4
Contributor

bf4 commented Apr 4, 2016

We have an internal API that uses an Accept: application/vnd.ourcompany.v2 header in requests.

We're writing a v3 and are planning on using JSON API, which specifies a request with Accept: application/vnd.api+json and response with Content-Type: application/vnd.api+json.

What the correct way to structure the Accept header with two vendor trees?

  • application/vnd.ourcompany.v3+json, application/vnd.api+json
  • application/vnd.ourcompany.v3+json; ext=jsonapi
  • application/vnd.ourcompany.v3+vnd.api+json
  • application/vnd.api+json; ext=ourcompany; version=3.0

etc?

I've been reading a bunch, but I can't figure out

Can you provide some guidance for this?

refs:

@ethanresnick

This comment has been minimized.

Show comment
Hide comment
@ethanresnick

ethanresnick Apr 5, 2016

Member

A media type in the vendor tree is used in the Accept header just like any other media type (i.e. there aren't vendor-type-specific rules). So the client just provides a comma-separated list of acceptable media types:

Accept: application/vnd.ourcompany.v3+json, application/vnd.api+json 

If the client wants to indicate that it prefers one type over another, it can use the q parameter, like so:

Accept: application/vnd.ourcompany.v3+json; q=0.5, application/vnd.api+json 

(The above header indicates that JSONAPI is preferred over vnd.ourcompany.v3+json. See here for more details on "q" values.)

Member

ethanresnick commented Apr 5, 2016

A media type in the vendor tree is used in the Accept header just like any other media type (i.e. there aren't vendor-type-specific rules). So the client just provides a comma-separated list of acceptable media types:

Accept: application/vnd.ourcompany.v3+json, application/vnd.api+json 

If the client wants to indicate that it prefers one type over another, it can use the q parameter, like so:

Accept: application/vnd.ourcompany.v3+json; q=0.5, application/vnd.api+json 

(The above header indicates that JSONAPI is preferred over vnd.ourcompany.v3+json. See here for more details on "q" values.)

@ethanresnick

This comment has been minimized.

Show comment
Hide comment
@ethanresnick

ethanresnick Apr 13, 2016

Member

@bf4 I re-read your question here after seeing your comment in #406, and I think I misunderstood it originally. Any media types listed in the Accept header are supposed to be independent of one another, so it's not appropriate to list multiple media types only to have the server use the presence of one type (i.e. the application/vnd.ourcompany.v3+json) as a signal to change the content it returns under another media type (i.e. application/vnd.api+json). If you can't use URI versioning, you should use a separate header, like X-API-Version: 3 (and then add Vary: X-API-Version).

Member

ethanresnick commented Apr 13, 2016

@bf4 I re-read your question here after seeing your comment in #406, and I think I misunderstood it originally. Any media types listed in the Accept header are supposed to be independent of one another, so it's not appropriate to list multiple media types only to have the server use the presence of one type (i.e. the application/vnd.ourcompany.v3+json) as a signal to change the content it returns under another media type (i.e. application/vnd.api+json). If you can't use URI versioning, you should use a separate header, like X-API-Version: 3 (and then add Vary: X-API-Version).

@bf4

This comment has been minimized.

Show comment
Hide comment
@bf4

bf4 Apr 14, 2016

Contributor

@ethanresnick Let me see if I understand you

Given a company has an API
And that API use the JSON API (media type: `application/vnd.api+json`)
And that the company is making breaking changes to the existing API
And so would like to use version the changes
Then the company should continue to specify their API media type, as it has not changed
And communicate the version in the
  URI (`example.com/v3/`) or 
  domain (`api3.example.com/`),
  via custom headers ( `X-API-Version: 3`, `Vary: X-API-Version`) OR 
  ask clients to understand a custom media type `application/vnd.ourcompany.v3+json` as including JSON API
BUT not as 
  `application/vnd.ourcompany.v3+json, application/vnd.api+json` nor
  `application/vnd.ourcompany.v3+json, ext=jsonapi` nor 
  `application/vnd.api+json; ext=ourcompany; version=3.0` nor
  `application/vnd.api+json; version = 3.0`
And that this is how users of JSON API should expect their APIs to evolve
Contributor

bf4 commented Apr 14, 2016

@ethanresnick Let me see if I understand you

Given a company has an API
And that API use the JSON API (media type: `application/vnd.api+json`)
And that the company is making breaking changes to the existing API
And so would like to use version the changes
Then the company should continue to specify their API media type, as it has not changed
And communicate the version in the
  URI (`example.com/v3/`) or 
  domain (`api3.example.com/`),
  via custom headers ( `X-API-Version: 3`, `Vary: X-API-Version`) OR 
  ask clients to understand a custom media type `application/vnd.ourcompany.v3+json` as including JSON API
BUT not as 
  `application/vnd.ourcompany.v3+json, application/vnd.api+json` nor
  `application/vnd.ourcompany.v3+json, ext=jsonapi` nor 
  `application/vnd.api+json; ext=ourcompany; version=3.0` nor
  `application/vnd.api+json; version = 3.0`
And that this is how users of JSON API should expect their APIs to evolve
@bf4

This comment has been minimized.

Show comment
Hide comment
@bf4

bf4 Apr 21, 2016

Contributor

So, I think I also misunderstood the spec w/r/t content negotiation.

The client must sends a request with Content-Type: application/vnd.api+json and the server respond with Content-Type: application/vnd.api+json.

But, regarding the Accept header

Clients that include the JSON API media type in their Accept header MUST specify the media type there at least once without any media type parameters.

So, the only requirement on the Accept header is that if a client has an Accept header that includes application/vnd.api+json, that it must appear without a media type parameter at least once.

So, there'd be no problem with a request with the headers Content-Type: application/vnd.api+json and Accept: application/vnd.ourcompany.v3, right?

The only problem there is that we must interpret application/vnd.ourcompany.v3 as the client accepting application/vnd.api+json, which is fine because we 'own' it.

Contributor

bf4 commented Apr 21, 2016

So, I think I also misunderstood the spec w/r/t content negotiation.

The client must sends a request with Content-Type: application/vnd.api+json and the server respond with Content-Type: application/vnd.api+json.

But, regarding the Accept header

Clients that include the JSON API media type in their Accept header MUST specify the media type there at least once without any media type parameters.

So, the only requirement on the Accept header is that if a client has an Accept header that includes application/vnd.api+json, that it must appear without a media type parameter at least once.

So, there'd be no problem with a request with the headers Content-Type: application/vnd.api+json and Accept: application/vnd.ourcompany.v3, right?

The only problem there is that we must interpret application/vnd.ourcompany.v3 as the client accepting application/vnd.api+json, which is fine because we 'own' it.

@bf4

This comment has been minimized.

Show comment
Hide comment
@bf4

bf4 Apr 18, 2017

Contributor

Noting that it appears from #406 and cerebris/jsonapi-resources#874 that Accept: application/vnd.api+json; version=3.0 or Accept: application/vnd.api+json; version=3.1 would appear to be a valid way for me to version my api without changing the mime type.

Contributor

bf4 commented Apr 18, 2017

Noting that it appears from #406 and cerebris/jsonapi-resources#874 that Accept: application/vnd.api+json; version=3.0 or Accept: application/vnd.api+json; version=3.1 would appear to be a valid way for me to version my api without changing the mime type.

@bf4

This comment has been minimized.

Show comment
Hide comment
@bf4

bf4 Jun 4, 2017

Contributor

@steveklabnik xrefs for a quick timeline of changes in points of view on the subject:

tl;dr Accept is for media types. Unless each API version happens to be a new media type, URL versioning is less confusing and just works better, if you need versioning at all

  • 2011 http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http#i_want_my_api_to_be_versioned

    The first thing that people do when they want a versioned API is to shove a /v1/ in the URL. THIS IS BAD!!!!!1. Accept solves this problem. What you're really asking for is "I'd like the version two representation of this resource." So use accept!

    It's a Vendor MIME Type. After all, we don't really want just any old JSON, we want my specific form of JSON. This lets us still have our one URL to represent our resource, yet version everything appropriately.

  • 2012 https://web.archive.org/web/20120229044244/http://blog.steveklabnik.com:80/posts/2011-07-03-nobody-understands-rest-or-http

    specifically don't agree that versioning the media type is how to properly version APIs. Hypermedia APIs should not actually use explicit versioning, but I'd rather see a version in the URI with HATEOAS than no HATEOAS and versioned media types.

  • 2013 #6 (comment)

    Versioning through accept headers is an anti-pattern. We won't be supporting it.

  • 2014 #68 (comment)

    How you version your API is completely orthogonal to JSON API itself, which is concerned about HTTP semantics and the arrangement of your JSON.

    At Balanced, we've versioned through the Accept header. If I were making a new project, I'd not version at all. Someone else may version through URLs. It doesn't really matter.
    URL versioning has nothing to do with HTTP. Accept may. It doesn't affect anything in JSON API directly.

  • 2016 #406 (comment)

    no, that's the version of JSON API itself. Which is what media type parameters are for: to parameterize the media type.
    I personally recommend "versioning" through URLs.

    I still think that using the media type to version is just plain incorrect. Media type parameters are for the media type, not for the underlying service.

    REST says nothing about URLs, let alone the structure of URLs.
    Version changes aren't always about only representation changes. If they were, then yes, the media type would be correct, as it would be about requesting a different representation.

    I specifically don't agree that versioning the media type is how to properly version APIs. Hypermedia APIs should not actually use explicit versioning, but I'd rather see a version in the URI with HATEOAS than no HATEOAS and versioned media types.

and for fun @brandur on REST/Hypermedia vs. GraphQL/RPC

  • 2013 https://brandur.org/accessible-apis
  • 2014 https://brandur.org/elegant-apis
  • 2017 https://brandur.org/api-paradigms

    hypermedia had a very hard time building any kind of traction
    After five years of strong evangelism at every API conference in the world and very little actual adoption, it’s a pretty safe bet that hypermedia isn’t going to be the next big thing.
    GraphQL is a fan favorite right now
    One possibility for the next big paradigm in APIs is just to make them a set RPCs (remote procedure calls) and use something like GRPC to generate libraries in a huge variety of languages that users can pull down and use at their leisure.
    Here’s one final strong opinion: religious adherence to REST is overrated and its perceived advantages have never materialized as fully as its proponents hoped. Whatever we choose next should aim to be flexible and efficient, and GraphQL seems like a good candidate for that

Contributor

bf4 commented Jun 4, 2017

@steveklabnik xrefs for a quick timeline of changes in points of view on the subject:

tl;dr Accept is for media types. Unless each API version happens to be a new media type, URL versioning is less confusing and just works better, if you need versioning at all

  • 2011 http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http#i_want_my_api_to_be_versioned

    The first thing that people do when they want a versioned API is to shove a /v1/ in the URL. THIS IS BAD!!!!!1. Accept solves this problem. What you're really asking for is "I'd like the version two representation of this resource." So use accept!

    It's a Vendor MIME Type. After all, we don't really want just any old JSON, we want my specific form of JSON. This lets us still have our one URL to represent our resource, yet version everything appropriately.

  • 2012 https://web.archive.org/web/20120229044244/http://blog.steveklabnik.com:80/posts/2011-07-03-nobody-understands-rest-or-http

    specifically don't agree that versioning the media type is how to properly version APIs. Hypermedia APIs should not actually use explicit versioning, but I'd rather see a version in the URI with HATEOAS than no HATEOAS and versioned media types.

  • 2013 #6 (comment)

    Versioning through accept headers is an anti-pattern. We won't be supporting it.

  • 2014 #68 (comment)

    How you version your API is completely orthogonal to JSON API itself, which is concerned about HTTP semantics and the arrangement of your JSON.

    At Balanced, we've versioned through the Accept header. If I were making a new project, I'd not version at all. Someone else may version through URLs. It doesn't really matter.
    URL versioning has nothing to do with HTTP. Accept may. It doesn't affect anything in JSON API directly.

  • 2016 #406 (comment)

    no, that's the version of JSON API itself. Which is what media type parameters are for: to parameterize the media type.
    I personally recommend "versioning" through URLs.

    I still think that using the media type to version is just plain incorrect. Media type parameters are for the media type, not for the underlying service.

    REST says nothing about URLs, let alone the structure of URLs.
    Version changes aren't always about only representation changes. If they were, then yes, the media type would be correct, as it would be about requesting a different representation.

    I specifically don't agree that versioning the media type is how to properly version APIs. Hypermedia APIs should not actually use explicit versioning, but I'd rather see a version in the URI with HATEOAS than no HATEOAS and versioned media types.

and for fun @brandur on REST/Hypermedia vs. GraphQL/RPC

  • 2013 https://brandur.org/accessible-apis
  • 2014 https://brandur.org/elegant-apis
  • 2017 https://brandur.org/api-paradigms

    hypermedia had a very hard time building any kind of traction
    After five years of strong evangelism at every API conference in the world and very little actual adoption, it’s a pretty safe bet that hypermedia isn’t going to be the next big thing.
    GraphQL is a fan favorite right now
    One possibility for the next big paradigm in APIs is just to make them a set RPCs (remote procedure calls) and use something like GRPC to generate libraries in a huge variety of languages that users can pull down and use at their leisure.
    Here’s one final strong opinion: religious adherence to REST is overrated and its perceived advantages have never materialized as fully as its proponents hoped. Whatever we choose next should aim to be flexible and efficient, and GraphQL seems like a good candidate for that

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