Custom header vs Path parameter

1,759 views
Skip to first unread message

Donghwan Kim

unread,
Jul 29, 2015, 4:16:37 AM7/29/15
to API Craft
Hi,

I have a problem where to put somewhat special parameter i.e. header or path. It is an application id which end-users create using our API, and none of API can't be used without the application id. If it should be included in path, URI will be in the form of '/v1/{applicationId}/resources' and if it should be included in header, URI will be in the form of '/v1/resources' with a required custom header, 'x-foobar-application-id: {applicationId}'. Because it is public, there is no security issue.

Here's characteristics of that parameter in question.

* A resource, Application, is a first-class citizen of our API and all the other resources belong to a specific application. Therefore, Using '/v1/apps/{applicationId}' as a base path is not meaningful in my opinion.
* It is always required so that it is not suitable to be included in query string in my opinion.
* It doesn't limit other API in terms of functionality. In other words, other APIs including '/v1/resources' have nothing to do with the application id.
* Some operations on Application resource might be required in the future e.g. '/v1/apps' but won't be public.
* It is a random string so that it might make a URI a little messy, however, I don't think it's important to make this decision.
* I followed the best practice for versioning from 'Web API Design - Crafting Interfaces that Developers Love' (A great resource!) and included it in the path i.e. '/v1'. However I'm not sure the same policy can be applied in this case.

What way do you prefer -- custom header or path parameter in this case?

Thanks,

-- Donghwan

Mike Kelly

unread,
Jul 29, 2015, 4:27:30 AM7/29/15
to api-...@googlegroups.com
The third option is to use subdomains, ie. {applicationId}.yourapi.com/foo which would allow you to do stuff like DNS load-balancing

Cheers,
M

--
You received this message because you are subscribed to the Google Groups "API Craft" group.
To unsubscribe from this group and stop receiving emails from it, send an email to api-craft+...@googlegroups.com.
Visit this group at http://groups.google.com/group/api-craft.
For more options, visit https://groups.google.com/d/optout.



--

Thomas Lörcher

unread,
Jul 29, 2015, 6:31:59 AM7/29/15
to API Craft, flowersi...@gmail.com
Hi Donghwan,

if I understand you correctly, the application id is some kind of API key to identify the different clients using your api (probably in order to track clients and to measure different metrics).
All clients are handled equally (concerning resource state) even if they are using different API keys.

In this case I think it's appropriate to put the id inside a custom http header (isn't there already a fitting header field, probably authentication header?).

If the server reacts differently on different API keys you should IMHO do it using the query parameter or the URI path since by using the same URL the response representation should always be the same 
on a GET request (referring to valid requests and responses, returning 2XX-response codes). This is especially important if you are going to exploit the whole power of REST by introducing 
different levels of caches (caches could be configured to evaluate HTTP-headers but they usually don't).
But I think there are different opinions on that topic.

Regards,
Thomas

Donghwan Kim

unread,
Jul 29, 2015, 7:58:07 AM7/29/15
to API Craft, thomas.l...@gmail.com
Hi Thomas,

The server reacts differently on different application id. For example, if you create your application whose id is 'abc', store some entities and retrieve some of them e.g. /v1/abc/entities/dogs, its status code will be 200 in your application (/abc/), but in other applications e.g. /v1/bcd/entities/dogs, it will be 404 since there is no such entity. (I included the app id in path according to your opinion here)

Anyway, could you elaborate on 'introducing different levels of caches' using URI?

Thanks for your answer!

-- Donghwan

Thomas Lörcher

unread,
Jul 29, 2015, 9:38:52 AM7/29/15
to API Craft, flowersi...@gmail.com
Hi Donghwan,

The server reacts differently on different application id. For example, if you create your application whose id is 'abc', store some entities and retrieve some of them e.g. /v1/abc/entities/dogs, its status code will be 200 in your application (/abc/), but in other applications e.g. /v1/bcd/entities/dogs, it will be 404 since there is no such entity. (I included the app id in path according to your opinion here)

are the entities and concomitant the data entries generally different for each api key or is this just a security measure where some of the clients aren't authorized to access / change the entities?

If there is a general difference between the data sets each client is getting (client A gets data A and client B gets data B) I'd highly recommend to seperate those into different resources. That implies there should also be different URLs for those resources.
By generating those resources the server has to build up the corresponding URLs and returning them to you, probably  '/v1/resources/42' for client A and ' /v1/resources/53' for client B.
After creating those resources the client is responsable to handle application state which means the client has to hold the URL and interact with the resource behind it if required.

By doing it that way you don't have to use the application id inside your API.


On the subject of caches:

If you want to receive the advantages of caching, your API should always indiscriminately carry back the same response for the same GET-requests on a resource (if not explicitely changed) for every client.
By same GET-request I mean a GET request on the same URL using the same media type (consider content negotiation).
That's one of the aspects of self-descriptive messages.

If the cache always gets different responses (for different application ids) how would he be able to cache that data.

By different levels of caches I mean for example proxy-caches on the client side, reverse-proxy- or API-gateway-caches on the server side and probably additional caches on the way between client and server.
There are also application cache like browser cache.
Every mentioned level could further have different levels of caches.

Once your API is caching-able you can take advantage of all those caches without having to change anything.
I'll probably write a thouroughly blog entry on that topic sometime.

Regards
Thomas


justin kruger

unread,
Jul 29, 2015, 10:39:33 AM7/29/15
to api-...@googlegroups.com, Donghwan Kim
REST is dead, Long Live REST.

I have worked on a number of projects at scale and I have to say I've never seen a project that is 100% REST.  Something always seems to bend the rule, but like any artist, 1st you learn the rules, and then you learn to break them.

Your question about AppID is such a situation.  You might want to think more pragmatically 1st and then think about form 2nd.

How long is your AppID?  is it 5 chars long, 10 chars, 26?  Long AppIDs might have different consequences.
What are your clients?  Are they modern browsers, all browsers, embeded systems, servers?

If you didn't impart the AppID, does it make sense to get Anonymous Data back? is it just for tracking Application Performance/ Behavior/ Analytics?  How do you know an 'Evil client' is not faking the AppID?

* URLs generally work below 2000 characters above that, many parts of the system start to break.

* Headers are not set-able in the in a redirect.

* Headers are more difficult to set cross domain with a CORs request, modern browsers IE11+ are fine, older browsers have varying rules with OPTION requests as preflight to a GET, POST, PUT, DELETE when doing cross domain requests.

* do you want to be able to validate an API call with a URL in testing? or use something like CURL to debug?  or as part of a script?  Not all code environments are created equal and headers are a layer of abstraction.

* how do you plan to route the traffic?  if an AppID is a contract to a device, you might want to route traffic based on the URL vs. a header which requires deeper inspection.  Good URLs never die, and embedded devices might need long lived API contracts, I think Netflix tries to service devices for 7-12 years.  Putting API version numbers and or AppIDs in the header is really clean, but it might be harder to maintain a server with API routes for that device long term, inspecting headers limits your proxy servers/ load balancer options, and might require you to do the header inspection at the App Logic layer.

--
You received this message because you are subscribed to the Google Groups "API Craft" group.
To unsubscribe from this group and stop receiving emails from it, send an email to api-craft+...@googlegroups.com.
Visit this group at http://groups.google.com/group/api-craft.
For more options, visit https://groups.google.com/d/optout.



--
--
--
Justin Kruger
Software Consultant 
& Javascript Architect -
San Francisco, CA

--
http://twitter.com/jdavid
http://www.linkedin.com/in/jdavid

Donghwan Kim

unread,
Jul 29, 2015, 10:41:16 AM7/29/15
to API Craft, thomas.l...@gmail.com
Hi Thomas,

are the entities and concomitant the data entries generally different for each api key or is this just a security measure where some of the clients aren't authorized to access / change the entities?
The former is right. If someone wants to develop yet another Evernote using our API, then the app would define entities like 'Note' and 'Notebook', and if someone wants to develop yet another Instagram, then the app would define entities like 'Picture' and 'Album'. And both apps might define 'Account' entity for user management. That's why we needed some identification of the application by either using custom header or path parameter.

Like you said, it is possible for the server to generate URI per resource like  '/v1/entities/42' instead of '/v1/{appId}/entities/notes', but Entity API is just one of APIs we provide for building application. For example, we are going to provide Account API per application for authentication and authorization management i.e. '/v1/{appId}/accounts'. So I think identification is still needed even though it's possible to do that without introducing it. However, I'm not sure I understood what you meant correctly. Please point me if i'm wrong.

Here is similar models:

As for the caches, I need more research on that part. I've thought about caching but couldn't spend time on that. Your blog entry will be a great help to me as well as other people for sure. Let me know your blog then I'll subscribe.

Thanks a lot!

-- Donghwan

Thomas Lörcher

unread,
Jul 29, 2015, 11:31:38 AM7/29/15
to API Craft, flowersi...@gmail.com
Hi Donghwan,

I think you understood well. :-)

For example, we are going to provide Account API per application for authentication and authorization management i.e. '/v1/{appId}/accounts'.
 
Well that's fair enough. To handle account and authorization information inside a resource is absolutely valid.

So I think identification is still needed even though it's possible to do that without introducing it.

Personally I'd put it in the header section but as justin mentioned there are additional aspects to be considered. An important thing justin also brought up:
Are you only going to identify the application for gathering specific analytics or do you want them to be securely authorized? In the latter case you should consider to introduce an authentication mechanism like OAuth.

 As for the caches, I need more research on that part. I've thought about caching but couldn't spend time on that. Your blog entry will be a great help to me as well as other people for sure. Let me know your blog then I'll subscribe.

First of all concentrate on your API. IMO optimizations like caching behavior can be approached later. 

Regards, 
Thomas

Donghwan Kim

unread,
Jul 29, 2015, 11:44:23 AM7/29/15
to API Craft, justin...@gmail.com
Hi Justin,

> How long is your AppID?  is it 5 chars long, 10 chars, 26?  Long AppIDs might have different consequences.
Maximum 36 since it would be in the form of UUID.

> What are your clients?  Are they modern browsers, all browsers, embeded systems, servers?
In most cases native mobile applications and HTML5 applications are the target.

> If you didn't impart the AppID, does it make sense to get Anonymous Data back? is it just for tracking Application Performance/ Behavior/ Analytics?  How do you know an 'Evil client' is not faking the AppID?
if a request has no application id, 401 will return. I guess my explanation wasn't clear enough. For the meaning of application id, please see https://groups.google.com/d/msg/api-craft/klC9znuvCRk/yOZJNE92EgAJ

> URLs generally work below 2000 characters above that, many parts of the system start to break.
I agree and am trying not to exceed 100 chars.

> Headers are not set-able in the in a redirect.
Does it mean some headers on an original request/response might be missing after redirection?

> Headers are more difficult to set cross domain with a CORs request, modern browsers IE11+ are fine, older browsers have varying rules with OPTION requests as preflight to a GET, POST, PUT, DELETE when doing cross domain requests.
Since I've developed a real-time application framework which supports even IE 6+, I'm well aware of such issues!

Anyway, I think I get your point.

Thanks,

-- Donghwan

justin kruger

unread,
Jul 29, 2015, 12:21:44 PM7/29/15
to Donghwan Kim, API Craft
It sounds like your AppID is part of your auth-token.  I would work off of those patterns.

AuthTokens, are commonly used as a query param or in the header.  Sometimes the AuthToken is just an AppID + Signed AppID.

Putting it in the header might be the right choice, and then using the token in the URL occasionally is good too.  URLs can get cached and logged as well, so on my current project we use a hash param #AuthToken={GUID} so that it's only visible to the browser.

On the backend you're able to get a refresh token by signing it with a secret.

Also, your API might allow for it to be used in a URL for debugging purposes, but your App might actually use it in the header in the common case.  You'll probably want to read up on ETags as you will need to configure your services to report proper ETags as the headers might be changing.

Cheers, and happy hunting.

Donghwan Kim

unread,
Jul 29, 2015, 9:51:17 PM7/29/15
to API Craft, justin...@gmail.com
Hi Justin,

Application id is used to identify a given operation's target application. In other words, if there is no application id or it's fake, it means a requested first-class citizen resource, application, doesn't exist rather than a request has no permission. Well... I should rethink which status code should be returned instead of 401. Sorry for the confusion.

For security, we are going to use header for sure. It would be 'Authorization' if we adopt OAuth 2 or 'x-foobar-session-token' if not. So a request whose a token is absent is an operation by a not logged in user. FYI, that user is not direct client of our API but client of an application, yet another Evernote, which our direct client builds using our API. So that I'm not sure OAuth 2 is appropriate or meaningful in our case. Internally, Account API provides role-based access control for our clients to control their applications' security policy, which is identified by the token.

Anyway, I think patterns you mentioned can be applied to the application id.

Thanks!

-- Donghwan

Donghwan Kim

unread,
Jul 29, 2015, 10:19:12 PM7/29/15
to API Craft, thomas.l...@gmail.com
Hi Thomas,

Personally I'd put it in the header section but as justin mentioned there are additional aspects to be considered. An important thing justin also brought up: Are you only going to identify the application for gathering specific analytics or do you want them to be securely authorized? In the latter case you should consider to introduce an authentication mechanism like OAuth.

First of all concentrate on your API. IMO optimizations like caching behavior can be approached later. 
I agree. Though, if a choice between path and header can affect the effectiveness of cache quite, I'd like to check it. For example, /v1/{appName}/entities/{entityName} is self-descriptive but /v1/entities/{entityName} requires header inspection because two different applications may use the same named entity. (Of course, there should be many other factors to affect this like media type)

Thanks as always!

-- Donghwan

Jan Schütze

unread,
Aug 13, 2015, 6:41:22 PM8/13/15
to api-...@googlegroups.com
Hi Donghwan

thanks for this interesting discussion!

I think in the way, you use the entities below the application it's
totally valid to put the applicationId into the path or use it as
subdomain (like mike kelly suggested).

E.g.:

https://myapp.example.org/entities/accounts
or https://example.org/applications/myapp/entities/accounts
or just https://example.org/myapp/entities/accounts (I would be
careful with that, because at which resource would you "create"
Applications?)

If you use the Authorization-Header or some kind of Token to
authenticate the User, take a look at JSON Web Tokens
(http://jwt.io/). It allows you to transport so-called "claims" from
one party to the other. This could be a place where you put your
applicationId, too.

Regards

Jan
> --
> You received this message because you are subscribed to the Google Groups
> "API Craft" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to api-craft+...@googlegroups.com.
> Visit this group at http://groups.google.com/group/api-craft.
> For more options, visit https://groups.google.com/d/optout.



--

http://dracoblue.net
Reply all
Reply to author
Forward
0 new messages