Skip to content

Instantly share code, notes, and snippets.

@servel333
Last active December 22, 2020 16:33
Show Gist options
  • Save servel333/00f1b118cbded8d07883b0d7590d0af8 to your computer and use it in GitHub Desktop.
Save servel333/00f1b118cbded8d07883b0d7590d0af8 to your computer and use it in GitHub Desktop.
API Query String Parameter Style Guide

Motivation

There is no clear standard (or this is a "yet another"?) for formatting query string parameters for various applications in an API.

Problems

Specify model attributes to filter on

  • &attribute[ATTRIBUTE-NAME]=ATTRIBUTE-VALUE

Specify model attributes to filter on with operators

  • Operators: greater than, greater than or equal, less than, less than or equal, in, etc...
  • &attribute[ATTRIBUTE-NAME][OPERATOR]=ATTRIBUTE-VALUE (Proposed)
  • &attribute[updated-at][gte]=2020-01-01 > SELECT ... WHERE updated-at >= DATE(2020-01-01)
  • &attribute[ATTRIBUTE-NAME]=[OPERATOR]ATTRIBUTE-VALUE (Proposed)
  • &attribute[ATTRIBUTE-NAME]=OPERATOR=ATTRIBUTE-VALUE (Proposed)
  • &attribute[updated-at]=gte=2020-01-01 > SELECT ... WHERE updated-at >= DATE(2020-01-01)
  • &attribute[categories][in]=a,b,c > SELECT ... WHERE categories IN [a, b, c]
  • &where[ATTRIBUTE-NAME]=ATTRIBUTE_VALUE

Specify model attributes to return in response body

  • &field[MODEL-NAME]=ATTRIBUTE-NAME
  • &field[]=ATTRIBUTE-NAME (Implies primary model name)
  • &field[]=name&field[]=updated-at > SELECT name, updated-at FROM ...
  • RULE: The model primary key (Typically id) is implied and always returned.

Include related models in response body

  • &include[]=MODEL-NAME&include[]=MODEL-NAME
  • &include=MODEL-NAME,MODEL-NAME

Pagination

  • &page[offset]=PAGE-OFFSET&page[limit]=PAGE-LIMIT
  • &page[token]=TOKEN
  • RULE: Next and previous page links are returned in the response body

Support nested attributes in all params

  • &attribute[ATTRIBUTE-NAME][ATTRIBUTE-NAME]=ATTRIBUTE-VALUE
  • &attribute[ATTRIBUTE-NAME.ATTRIBUTE-NAME]=ATTRIBUTE-VALUE

Support querying by date

  • Require ISO 8601 format

Header to indicate query string parameter format

  • X-Query-Parameter-Type: application/vnd.standard-qsp.draft-1
  • X-Query-Parameter-Type: application/vnd.standard-qsp.v1

Examples

  • /users?includes=orders&fields=id,email&fields[orders]=id,user-id,total,item-count

Notes

  • How data is returned in the response body is up to the API implementation.

Use of underscore (_)

Apparenty underscore (_) is not liked in the query.

$ curl "localhost:3000/tests/echo?attribute[updated_at][gte]=2020-01-01"
curl: (3) bad range in URL position 37:
localhost:3023/tests/echo?attribute[updated_at][gte]=2020-01-01

References

Not Escaped: A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #

Not Escaped A-Z a-z 0-9 - _ . ! ~ * ' ( )

Implementation specific query parameters MUST adhere to the same constraints as member names with the additional requirement that they MUST contain at least one non a-z character (U+0061 to U+007A). It is RECOMMENDED that a U+002D HYPHEN-MINUS, “-“, U+005F LOW LINE, “_”, or capital letter is used (e.g. camelCasing).

If a server encounters a query parameter that does not follow the naming conventions above, and the server does not know how to process it as a query parameter from this specification, it MUST return 400 Bad Request.

  • ?q={"name" : {"$not" : "Joe"}}
  • ?q={"name" : {"$in" : ["Joe", "Jane", "Donald"]}}
  • ?q={"name" : {"$nin" : ["Joe", "Jane", "Donald"]}}
  • ?q={"name" : {"$regex" : ".Joe*"}}
  • ?q={"$or": [{"name": "Jane"}, {"name": "Donald"}]}
  • ?q={"$and": [{"name": "Jane"}, {"last-name": "Cassidy"}]}
  • $not: Negation logical operator {"field" : {"$not" : val}}
  • $in: Match any value in array {"field" : {"$in" : [value1, value2, ...]}}
  • $nin: Not match any value in array {"field" : {"$nin" : [value1, value2, ...]}}
  • $regex: Match field {"field" : {"$regex" : ".*"}}
  • $or: Logical operator {"$or": [{"status": "GOLD"}, {"status": "SILVER"}]}
  • $and: Logical operator {"$and": [{"status": "GOLD"}, {"sales": 1000}]}
  • ?q={"salary": {"$gt": 10000}}
  • ?q={"salary": {"$gte": 10000}}
  • ?q={"salary": {"$lt": 10000}}
  • ?q={"salary": {"$lte": 10000}}
  • ?q={"salary": {"$bt": [5000, 7500]}}
  • ?q={"field": {"$exists": true}}
  • ?q={"field.0": {"$exists": true}}
  • ?q={"contact":{"$elemMatch":{"name":"Anderson", age:35}}}
  • ?q={"$distinct": "age"}&sort=age
  • $gt > {"salary": {"$gt": 10000}}
  • $gte >= {"salary": {"$gte": 10000}}
  • $lt < {"salary": {"$lt": 10000}}
  • $lte <= {"salary": {"$lte": 10000}}
  • $bt >= value <= {"salary": {"$bt": [5000, 7500]}}
  • $exists Check if field exists {"field": {"$exists": true|false}}
  • $exists (array) Check if array field exists or is empty {"field.0": {"$exists": true|false}}
  • $elemMatch Array element matching {"contact":{"$elemMatch":{"name":"Anderson", age:35}}}
  • $distinct Array with unique element values {"$distinct": "name"}
  • between two dates {"_changed":{"$gt":{"$date":"2016-08-01"},"$lt":{"$date":"2016-08-05"}}}
  • older than the time just now {"startat":{"$lt":{"$date":"$now"}}}
  • $now just now
  • $currentMinute start of last minute
  • $currentHour start of last hour
  • $currentDate start of current day
  • $today start of current day
  • $tomorrow start of next day
  • $yesterday start of day before
  • $currentWeek start of this week (sunday)
  • $currentMonth start of this month
  • $currentYear start of this year
  • $nextWeek start of next week (sunday)
  • $nextMonth start of next month
  • $nextYear start of next year
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment