Is it possible to route requests to different applications via Content-Type?

5,946

Solution 1

Nginx's idiomatic approach to this kind of problems is via map. Please see my answer at StackOverflow.

Basically, you define a map in http section

map $any_variable $my_upstream {
  # Default value:
  default upstream1;

  # Exact match:
  application/vnd.vendorname+json;v=1 upstream2;

  # Regexp:
  ~^application.*vnd.vendorname-v1\+json upstream3;
}

You may mix exact matches and regexps in one map.

Then you simply use $my_upstream in you server or location section(s):

location / {
  proxy_pass http://$my_upstream$uri;
}

Nginx evaluates map variables lazily, only once (per request) and when you are using them.

Solution 2

Sure; Apache's mod_rewrite could do this with a little bit of RewriteCond, though I'm a bit too rusty to give you an example off the top of my head. In nginx, though, it'd look something like the following (assuming you had two upstreams defined; one for your jsonapp and the other for... otherstuff):

if ($content_type = application/vnd.vendorname-v1+json) {
    proxy_pass http://jsonapp/
    break;
}
proxy_pass http://otherstuff/
Share:
5,946

Related videos on Youtube

Adam Lassek
Author by

Adam Lassek

Updated on September 18, 2022

Comments

  • Adam Lassek
    Adam Lassek almost 2 years

    I'm designing a JSON API, and I'd like to version the API using content negotiation of some kind. I'm currently planning on using Vendor MIME Types to do this.

    While I can definitely do this at the application level, I'm thinking it would be best to make this happen at the HTTP server level. Is this possible with Apache or nginx?

    The Content-Type would look something like: application/vnd.vendorname-v1+json or possibly using parameters: application/vnd.vendorname+json;v=1

    • Alexander Azarov
      Alexander Azarov almost 13 years
      Content-type is a response's header. In order to select a backend based on request, you must rely on some header from request. Which one?
    • Austen Holmes
      Austen Holmes almost 13 years
      The Accept: header, which the client uses to specify which Content-Types it would like to receive when performing content negotiation.
  • Adam Lassek
    Adam Lassek almost 13 years
    Would this proxy be transparent to the outsider? I want both applications to be accessible by the same url.
  • womble
    womble almost 13 years
    Yes, of course, that's the whole point of a proxy.
  • kolbyjack
    kolbyjack almost 13 years
    Be careful when using variables with proxy_pass. From the wiki entry: "A special case is using variables in the proxy_pass statement: The requested URL is not used and you are fully responsible to construct the target URL yourself."
  • Adam Lassek
    Adam Lassek almost 13 years
    but what, exactly, would jsonapp and otherstuff be in your example? Should I create entries in /etc/hosts and map those to the two different apps first? (I'm new to nginx, sorry)
  • Adam Lassek
    Adam Lassek almost 13 years
    I disagree. Content negotiation should be the job of the HTTP server. This will actually greatly simplify API development. While misconfiguration could indeed cause a problem, that possibility is not limited to this use case.
  • Adam Lassek
    Adam Lassek almost 13 years
    More information about the API: we will be developing a JSON API for AJAX clients using Sinatra+Rack. If API versioning is done through content negotiation, then separate versions can be deployed in isolation of one another. This is a simple, elegant design following REST principles. What you describe would actually create more dependencies between versions.
  • hookenz
    hookenz almost 13 years
    I didn't say you couldn't negotiate the content. PHP does that. I'm talking about the version number!
  • Adam Lassek
    Adam Lassek almost 13 years
    The version number would define what content you get, such as breaking changes to the api. That is why I think content negotiation is appropriate.
  • Adam Lassek
    Adam Lassek almost 13 years
    (to clarify further, when I say 'content' I mean the specific format of the JSON being returned. For instance, the resource location /people/:id may not change between v1 and v2, but the format of the JSON you get back may change dramatically. The 'identity' of the resource hasn't changed, but it's representation has.)
  • womble
    womble almost 13 years
    They should be whatever you've defined your "upstreams" to be; see wiki.nginx.org/NginxHttpProxyModule#proxy_pass and wiki.nginx.org/HttpUpstreamModule