Custom Headers vs Query String

I recently had a good discussion with my colleagues on a REST (piggybacking on  HTTP) service API design.  Quickly a very simple question piqued the interest of us all –  “what information should be requested in the (custom) headers and what information should be requested in the query string”.

Taking a step back, it is worth asking why this question would even arise? It is because both, http headers and query string parameters,  are valid input vehicles for a REST resource that influence the response it returns.

It is helpful to take one more step back to bring in two REST concepts to the fore to set up the context for our answer:

  • A single resource could be a collection of entitiesFielding defines “a resource R is a temporally varying membership function MR(t), which for time t maps to a set of entities, or values, which are equivalent.”
  • A REST ecosystem is a collection of resources.

We should examine a few characteristics (below) of the parameter under consideration to find a home for it:

To Restrict or To Offer Filters

As mentioned earlier, a resource is a collection of entities.  Both headers and query string parameters play a role in selecting a subset of entities from the collection.  If the need is to restrict or preselect a subset unbeknownst to the client, then headers should be used. On the other hand, if the need is to allow the client to choose a subset, then query string parameters must be used.

For example: The /orders is a resource of order entity collection in a store.

  • When a customer accesses /orders,  he/she is only presented with the orders he/she created.
  • However, when the store manager accesses /orders, he/she is presented with all the orders.

In the above case,  the resource pre-filtered the order entity collection by using the contextual information (store manager or customer).

Query strings can be used by both of them further narrow the order entities in this fashion /orders?date=today

  • The customer is presented with the orders he/she placed today.
  • The store manaager is presented with all the orders by all customers placed today.

In the above case, the user (store manager or customer) is specifically request a subset of the order entities.

More than filtering

The sweet spot for query string parameters is resource filtering (like the cases we talked about earlier). For other requirements  we need to start from headers and work towards query string parameters (i.e if we have to).

HTTP offers a wide variety of standard headers addressing a wide variety of needs:

  • Some, like Content-Type, describe the representation used.
  • Some others, like If-Modified-Since, influence resource caching.
  • And only a few, like Authorization and Range, could have an “effect” similar to filtering of collections of entities.

HTTP headers should be used to send contextual information about the request to the resource.

There is nothing in REST specification that limits us to the standard headers.  It should be fine to roll our own custom header in case of a specific justifiable need – HTTP itself is designed to be extensible.

Specificity to a resource

Query string parameters have a strong correlation to the properties of the entity behind a resource. For example:  “order_date” property belongs to a the order entity and it is a natural fit for a query string. This fits in nicely the filtering view of resources – obviously it logical to filter entities with the properties on it.

On the other hand, headers seldom have a direct correlation to specific properties of the entity behind a resource.

If the parameter under consideration has a strong affinity to a resource, then placing it in the header is not the right choice.

Sphere of influence

Query string’s specificity to a resource also limits it’s influence (so simply reusability) to a single source (very few times more than one).

In the cases where the parameter under consideration is expected to be applicable to all resources in the ecosystem, then locating this parameter in the header makes most sense. It is worth emphasizing that “being applicable” is not the same as mandatory.


Another hint one could use to determine if a parameter belongs to in the query string or the header is by asking who/when/where provides the value for the parameter.

Header parameters are typically added out-of-band by applications like user agents and/or proxies. If you need to allow message intermediaries to add the parameter to the message, then it should be located in the header.

In case of query string,  parameters can usually be traced back to some kind of direct input accepted by the system to satisfy a request. Query string remains untouched by intermediate proxy layers.

In other words, query string is reserved for end users/applications that are invoking resource. On the other hand headers are reserved for applications and intermediaries that are facilitating this invocation.


At the core of it, to locate parameter in a header or a query is not an exact science. However, the above guidelines could help lending some objectivity to most decisions.


2 thoughts on “Custom Headers vs Query String

  1. Shlomi Cohen

    Nice article , really like how you cover all aspect. but caching was not mentioned.
    and i think is important .as far as i know header do not participate in browser cache. is that mean we need to design URIs differently for API and for browsers ?

    1. ryerramilli Post author

      Yes, agree with you regarding browsers.

      However, if we stay true to HTTP, then the clients are expected to the respect the “VARY” header. This informs the client which headers should be considered to cache the response.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s