I am implementing a REST-like API and have just faced an interesting problem. There is a need to provide a resource with an open list of query parameters to filter the results.
For example:
GET /api/items?field1=value1&field2=value2
Field names are configurable, so I don’t have the complete list of possible names.
There are also parameters with special meaning, e.g. orderBy=field5
The problem is when there is a field with the same name as one of the pre-defined parameters. The API has to somehow distinguish between them.
Many command-line programs use two hyphens (“–“) to mark the end of options and start of arguments. I think of something analogous in URLs.
Is there any good practice in this subject?
3
An easy solution is to add a prefix to all the query fields (or at least the customized). In my case the fields can be in different classes, e.g. “core” or “custom” so it is convenient to use prefixes to differentiate them. For example, “core.field1”, “custom.field10”. As a side effect, it will resolve the problem with conflicts.
If someone adds a field called orderBy, it still will be able to be used for filtering without any conflict with the special parameter of the same name:
custom.orderBy=something&orderBy=field1
You can also mix the special fields with the field names. e.g.
/api/items?field1.orderByDesc=value1&field2=value2&field3.orderByAsc=value3
With this approach, you keep the field-specific filters close to the field without having to scan a separate parameter’s value. Of course if you have some non-field related special params, such as pagination requests, then the “filters” special param is your best bet. You can make it less prone to conflicts by prefixing an improbable character sequence like
/api/items?field1.orderByDesc=value1&field2=value2&field3.orderByAsc=value3&z9x8y7rowStart=100&z9x8y7count=50
The z9x8y7 approach is similar to how PHP prefixes a $ before variable names.
On a different note, you may want to add a version number in the API itself, something like
/api/v1/items?........
This will allow you to keep multiple versions of your API alive, thus giving your consumers time to convert to a new version of your API when you release a new API. Some examples : http://www.lexicalscope.com/blog/2012/03/12/how-are-rest-apis-versioned/
2