@datawheel/canon-logiclayer

API logic using mondrian-rest-client.

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
@datawheel/canon-logiclayer
261110.6.1a year ago6 years agoMinified + gzip package size for @datawheel/canon-logiclayer in KB

Readme

Canon Logic Layer
The Canon Logic Layer is a REST API that simplifies queries to a mondrian cube using shorthand and introspective logic. This documentation contains installation instructions, basic usage examples, and explanations of the custom logic and settings that can be provided through the canon.js file in the root directory of a project.

Contents


Installation

npm i @datawheel/canon-logiclayer

An environment variable must be set to tell the logic layer which mondrian cube to use. For example, this would hook into the Data USA cube:
export CANON_LOGICLAYER_CUBE=https://olympic-api.datausa.io/

Additionally, logging can be enabled with the following variable:
export CANON_LOGICLAYER_LOGGING=true

If you would like to only log errors, use the following:
export CANON_LOGICLAYER_LOGGING='error'


Once the package has been installed on any site using @datawheel/canon-core, and the CANON_LOGICLAYER_CUBE environment variable has been set, the canon core server will automatically hook up the necessary cache and api routes for the logic layer.

Usage

The logic layer exposes an endpoint at /api/data that will return JSON based on a series of query arguments. As simple example, using the Data USA cube, this endpoint would return population data for Massachusetts:
/api/data?measures=Total Population&State=04000US25

{
  "data": [{
      "ID Year": 2016,
      "Year": "2016",
      "ID State": "04000US25",
      "State": "Massachusetts",
      "Total Population": 6811779
    },
    {
      "ID Year": 2015,
      "Year": "2015",
      "ID State": "04000US25",
      "State": "Massachusetts",
      "Total Population": 6794422
    },
    {
      "ID Year": 2014,
      "Year": "2014",
      "ID State": "04000US25",
      "State": "Massachusetts",
      "Total Population": 6745408
    },
    {
      "ID Year": 2013,
      "Year": "2013",
      "ID State": "04000US25",
      "State": "Massachusetts",
      "Total Population": 6692824
    }
  ],
  "source": [{
    "measures": [
      "Total Population"
    ],
    "annotations": {
      "source_name": "Census Bureau",
      "source_link": "http://www.census.gov/programs-surveys/acs/",
      "dataset_name": "ACS 1-year Estimate",
      "table_id": "B01003"
    },
    "name": "acs_yg_total_population_1",
    "substitutions": []
  }]
}

Reserved Keywords

|keyword|description|default| |---|---|---| |captions|If the cube in use has multiple captions for dimensions, use this to set the desired output (ie. captions=es for DataChile).|"false"| |drilldowns|A comma-separated list of drilldowns that should match to a level in a dimension.|""| |limit|If defined, will only return the first X results.|""| |measures|A comma-separated list of measure names to return. This is the only required keyword, and is used as the basis to determine which cubes should be queried.|""| |order|The variable on which to order the final JSON results.|"Year"| |parents|A boolean value, which determines whether or not to return the dimension parents from the query.|"false"| |properties|A comma-separated list of properties to fetch for the provided dimensions.|""| |sort|The sort direction for the order property. Can be either "desc" or "asc"|"desc"| |Year|Which years to return from the database. In addition to supported comma-separated values (ie. "2015,2016"), there is also a preset list of shorthands: "latest", "previous", "oldest", "all"|"all"|

Cuts and Filters

Any keyword argument that is not recognized from the above list is considered either a cut or a filter, depending on if the keyword is a dimension or measure, respectively. In the Data USA example above, the State=04000US25 is cutting the State dimension on the ID 04000US25. For filtering by a measure, you can use >= and <= in addition to standard equalality (=).

Aliases

In addition to the reserved words, the canon.js file in the root directory of your project can contain a list of aliases to use for any keyword. For example, this config allows the new Data USA api to retain some of the legacy naming conventions from the old api:
module.exports = {
  logiclayer: {
    aliases: {
      "CIP": "cip",
      "Geography": "geo",
      "measures": ["measure", "required"],
      "PUMS Industry": "naics",
      "PUMS Occupation": "soc",
      "University": "university",
      "Year": "year"
    }
  }
};

Custom Cube Filtering

When determining which cubes to use for specific variables, there may be multiple cubes that match a given criteria. By default, the logic layer will simply select the first cube in an alpha-sorted array by cube name. If custom logic is needed, this logic cna be defined in the canon.js configuration file.
For example, the Data USA cube contains tables for ACS 1-year estimates and 5-year estimates, with the estimate year ending the table name (ie. *_5 and *-1). A cube filter consists of 2 parts: a key function to group the table for inspection, and a filter function that returns the correct cube. Filters will be chained sequentially based on their order in the Array set on cubeFilters. This example uses a custom cache (passed as the third argument) in order to chose the table pased on the requested locations population.
const d3Array = require("d3-array");

module.exports = {
  logiclayer: {
    cubeFilters: [
      {
        filter: (cubes, query, caches) => {
          const {pops} = caches;
          const ids = d3Array.merge(query.dimensions
            .filter(d => d.dimension === "Geography")
            .map(d => d.id));
          const bigGeos = ids.every(g => pops[g] && pops[g] >= 250000);
          return cubes.filter(cube => cube.name.match(bigGeos ? /_1$/g : /_5$/g));
        },
        key: cube => cube.name.replace(/_[0-9]$/g, "")
      }
    ]
  }
};