LCBO API

Follow on Twitter!

Conventions

Responses

The default response format for the API is JSON. This means that you don’t need to specify JSON in an Accept header or as an extension (.json) if that is the format you intend to request. Every response from the API is wrapped in a “container” that in its most basic form looks like this:

{
  "status": 200,
  "message": null,
  "result": ...
}

This allows the API to return meta information along with the data you are requesting. For example, in the case of a Stores with Product request the product object is returned with list of stores so that your application does not need to perform an additional request to obtain store information.

JSON-P

JSON-P stands for “JSON with padding” which is a very confusing way of saying JSON wrapped in a Javascript function call; I like to think of it as JSON-JS. It is used to circumvent browser security limitations when trying to access resources via Javascript from a different host than the containing page. That means you can use it to load LCBO API resources on a page that is not hosted on lcboapi.com, such as your website!

One of the limitations to JSON-P is that the HTTP status can not be properly set to an error level because the <script> element that is dynamically written to the page will fail to load. Because of this all JSON-P requests return a 200 HTTP status code, regardless of the actual status. However, the "status" node in the response container always indicates the real status.

To use JSON-P simply provide a callback parameter to your query. For example, to search products and return JSON-P you would request:

/products?q=cider&callback=setJSON

This will return the normal JSON response but wrap it in a function call:

setJSON({"status":200, "message":null, "response": ...});

You can optionally specify a .js file extension for the resource, but the Content-Type header will always be set to text/javascript when returning JSON-P. For example the following request URI is the same as the one above.

/products.js?q=cider&callback=setJSON

Pagination

When the API returns collections of items (stores, products, or inventories) it will paginate the results. You can control the number of items per page through the per_page parameter.

A typical pager object looks like this:

{
  "records_per_page": 20,
  "total_record_count": 608,
  "current_page_record_count": 20,
  "is_first_page": false,
  "is_final_page": false,
  "current_page": 5,
  "current_page_path": "/stores?page=5",
  "next_page": 6,
  "next_page_path": "/stores?page=6",
  "previous_page": 4,
  "previous_page_path": "/stores?page=4",
  "final_page": 31,
  "final_page_path": "/stores?page=31"
}

It contains all of the information you need (and more) to navigate through the pages in the result set.

CSV and TSV Responses

Many resources can be returned as CSV (comma separated values) or TSV (tab separated values). These results can then be easily imported into spreadsheet software such as Apple Numbers or Microsoft Excel. To return a resource in CSV or TSV format simply append the .csv or .tsv extension to the resource URI:

/products.csv?order=price_in_cents.desc

Errors

When an error occurs the response will look something like this:

{
  "error": "bad_query_error",
  "message": "A value supplied for the order parameter (id.desk) is not valid. It contains an invalid sort order (desk) for (id) try using: id.desc or id.asc instead.",
  "result": null,
  "status": 400
}

Error messages are always as descriptive as possible; one of the design goals for LCBO API is to make experiential learning (learning by trial and error) as easy as possible. There are a few different types of errors:

  • no_results_error: The geocoder returned no geometry for the geo query.
  • over_limit_error: The geocoder has reached its daily limit of requests.
  • geocoder_error: The geocoder can’t geocode the query it was provided.
  • not_found_error: A resource was not found (404)
  • bad_query_error: One (or more) of the supplied query parameters is wrong.
  • jsonp_error: Supplied callback is not a valid format, or JSON-P is not being used correctly.