What makes a great API definition?
There are only two hard things in Computer Science: cache invalidation and naming things.
Phil Karlton
Why is it so hard to name things? Or more precisely, why is it so hard to pick a set of symbols that reliably communicate the intended meaning to the interpreting audience? And why is it particularly difficult to name things within information systems?
Let’s unpack the three tensions of naming that excellence that underly these difficulties:
Bridging the Tech / Business divide
Ill considered names exacerbate divides. Usually the culprit is a technologist lazily exporting their database schema.
Excellence requires building definitions around deep understanding of the words used by domain practitioners and the meaning attached to these words.
At the same time, definitions must be usable. This means implementing a definition in such a way that it can be efficiently modeled and typed.
Balancing stability with extensibility
Well developed definitions are stable but extensible. Too much change creates chaos. Rigidity means that the world will pass you by.
Goldilocks specificity
Too general, and what’s the point. Too specific and what’s the point. The point of a well defined definition layer is the “not too hot”, “not too cold” level of compromise of standardization enabling the specific needs of individual use cases.
Let’s take an example: defining an “Instrument” in the asset and wealth management industry
First, what is it that we are actually trying to define here. Going from, "we all implicitly know what this is" to "this is what we are actually trying to define here" is difficult.
// An Instrument is a financial asset or series
// such as an equity, bond, commodity, currency pair or index.
message Instrument {
// TODO: let's define an instrument
}
Next, let's decide how this thing will be named. Immediately things get tricky. The name itself carries information. Across Alis Exchange we strongly encourage the use of Resource Oriented Design naming conventions (read more here) to help users more easily intuit the collection or sub-collection a resource belongs to and anticipate how to use and work with these names.
In this case, any user can rely on the fact that the ID portion of an instrument name is either a FIGI from the OpenFIGI database or a custom created FIGI that obeys the same naming conventions (read more here) and reason accordingly.
// An Instrument is a financial asset or series
// such as an equity, bond, commodity, currency pair or index.
message Instrument {
// The instrument name is the unique identifier across organisations.
// Format: instruments/{instrument}.
// {instrument} must be a valid Bloomberg or custom FIGI,
// as defined by www.openfigi.com..
string name = 1;
}
Now we start to add the fields that define an Instrument
object. The security description and display_name intentionally deviate from the OpenFIGI specification. We thoughtfully decided to deviate from the definition after weighing the needs of users of the system against the value of adhering to a global specification.
For some fields, it is also helpful to enumerate possible values. For example, we want to restrict Market Sector to a set of choices that data producers and consumers can more easily reason about. Safety and usability often go hand in hand.
// Instrument is a resource in the IN domain.
message Instrument {
// ...
// Figi Type. Either a global or custom FIGI, else set to unspecified
FigiType figi_type = 2;
// Human readable display name
string display_name = 3;
// Security Description
string description = 4;
// Market Sector
// The asset class/category of the particular instrument
// Format: EQUITY, MONEY_MARKET, etc.
MarketSector market_sector = 5;
// The instrument market sector
enum MarketSector {
// Market Sector not specified
MARKET_SECTOR_UNSPECIFIED = 0;
// Commodities
COMMODITY = 1;
// Corporate Bonds
CORPORATE = 2;
// Currency
CURRENCY = 3;
//...
}
It is important to know where to draw the boundary of a definition. For example, in an early version of the API definition we added fields that would allow users to store instrument data relevant to their compliance process. We later realized that this data would be better managed in a separate service and therefore decided to safely deprecate the field.
// Instrument is a resource in the IN domain.
message Instrument {
// ...
// Compliance attributes
// A set of attributes specific to the compliance domain
Compliance compliance = 13 [deprecated = true];
// All compliance related attributes.
message Compliance {
// UCITS attributes.
Ucits asisa = 1;
// ...
}
And finally, a well designed API bridges the Tech / Business divide by well documenting domain relevant information within the API. For example, the Instrument
definition has a set of fields that enable the user to store associations to other external identifiers used by market data providers (such as SEDOL, CUSIP, RIC and PermId). These fields are well documented with the information a user needs to understand the field and a reference to sources of further information where applicable.
// Instrument is a resource in the IN domain.
message Instrument {
// ...
// External identifiers
ExternalIDs external_ids = 8;
// External identifiers
message ExternalIDs {
// figi as defined by www.openfigi.com.
// If no figi is provided, a custom figi will be created using the remaining attributes.
string figi = 1;
// Composite Financial Instrument Global Identifier - The Composite Financial Instrument Global Identifier
// (FIGI) enables users to link multiple FIGIs at the trading venue level within the same country or market
// in order to obtain an aggregated view for an instrument within that country or market.
string composite_figi = 2;
// Share Class Financial Instrument Global Identifier - A Share Class level Financial Instrument Global Identifier
// is assigned to an instrument that is traded in more than one country. This enables users to link multiple
// Composite FIGIs for the same instrument in order to obtain an aggregated view for that instrument across all
// countries (globally).
string share_class_figi = 3;
// ISIN
// An International Securities Identification Number (ISIN) is a code that uniquely identifies a specific
// securities issue.
string isin = 4;
// SEDOL (Stock Exchange Daily Official List)
// a list of security identifiers used in the United Kingdom and Ireland for clearing purposes.
// The numbers are assigned by the London Stock Exchange, on request by the security issuer.
string sedol = 5;
// CUSIP
// a nine-digit numeric (e.g. 037833100 for Apple) or nine-character alphanumeric (e.g. 38259P508 for Google)
// code that identifies a North American financial security for the purposes of facilitating clearing and
// settlement of trades.
// https://en.wikipedia.org/wiki/CUSIP
string cusip = 6;
// RIC (Reuters instrument code)
// is a ticker-like code used by Refinitiv to identify financial instruments and indices.
// https://en.wikipedia.org/wiki/Reuters_Instrument_Code
string ric = 7;
// Primary RIC (Reuters instrument code)
// is a ticker-like code used by Refinitiv to identify financial instruments and indices.
// https://en.wikipedia.org/wiki/Reuters_Instrument_Code
string primary_ric = 8;
// Bloomberg Ticker
// a string of characters or numbers to identify a company or entity uniquely in Bloomberg.
string bloomberg_ticker = 9;
// MSCI Security Code is a unique identifier assigned to each security by MSCI.
string msci_sec_code = 10;
// A Central Index Key or CIK number is a number given to an individual, company, or foreign government by
// the United States Securities and Exchange Commission. The number is used to identify its filings in
// several online databases, including EDGAR.
string cik = 11;
// InvestOne Id
// InvestOne is an investment accounting solution for institutional asset managers.
string invest_one = 12;
// Morningstar SecId
string morningstar_sec_id = 13;
// Morningstar CompanyId
string morningstar_company_id = 14;
// MCH Id
// MCH (Multi-Currency Horizon) is an investment accounting solution for institutional asset managers.
string mch = 15;
// Multifonds Id
// Multifonds is an investment accounting solution for institutional asset managers.
string multifonds = 16;
// Fundamental Id
// Fundamental is an investment accounting solution for institutional asset managers.
string fundamental = 17;
// Morgan Stanley Id
// Morgan Stanley is an investment trading solution provider for institutional asset managers.
string morgan_stanley = 18;
// JSE Alpha Code
// The ticker used by the Johannesburg Stock Exchange
string jse_alpha_code = 19;
// Refinitiv PermID
// PermIDs are open, permanent and universal identifiers where underlying attributes capture the
// context of the identity they each represent.
// https://permid.org/
string perm_id = 20;
// Datastream Symbol
string datastream_symbol = 21;
// IEX Identifier
string iex_id = 22;
}
// ....
}