Skip to main content

The design challenge

Building data has traditionally been queried with SPARQL, a powerful graph query language that almost nobody outside academia uses. Tacit’s API design challenge was to preserve SPARQL’s three key capabilities while making them accessible through protocols developers already know.

Three capabilities preserved

1. Class hierarchy inference

SPARQL uses a/rdfs:subClassOf* to match any subclass of a given type. Tacit exposes this through the is argument:
SPARQLTacit GraphQL
?x a/rdfs:subClassOf* brick:HVAC_Equipmentequipment(is: "HVAC_Equipment")
?x a/rdfs:subClassOf* brick:Temperature_Sensorpoints(is: "Temperature_Sensor")
Same resolution, different syntax. Learn more in class hierarchy.

2. Transitive traversal

SPARQL uses brick:feeds+ to follow relationship chains to any depth. Tacit exposes this through upstream and downstream fields:
SPARQLTacit GraphQL
?equip brick:feeds+ ?zonezones { upstream { name type } }
?zone ^brick:feeds+ ?sourceequipment { downstream { name type } }
Same traversal, declarative fields instead of property path syntax. Learn more in upstream and downstream.

3. Pattern matching

SPARQL uses triple patterns to describe relationship shapes. Tacit expresses patterns through nested GraphQL field selections:
SPARQLTacit GraphQL
Multiple ?x ?rel ?y patternsNested field selections
FILTER(STRSTARTS(...))is: "Temperature_Sensor" (Brick class filter)
Combined patterns in WHERE clauseCombined nesting + filters
The nesting structure is more constrained than SPARQL (hierarchical, not arbitrary graph shapes), but covers the patterns that 99% of building queries need. Learn more in relationships and traversal.

What we chose not to preserve

Two SPARQL capabilities are deliberately excluded:
  • Cycle detection: finding circular relationships (A feeds B feeds C feeds A). These are rare in building data and indicate modeling errors rather than useful patterns.
  • Arbitrary graph patterns: matching non-tree shapes where multiple variables connect in loops. These represent less than 1% of building queries and are not supported through the API.

Why GraphQL for reads

GraphQL was chosen over REST for the read surface because building queries are naturally hierarchical and variable-shaped:
  • Variable depth: equipment chains vary from 2 to 6 levels deep
  • Variable breadth: one AHU might have 5 points, another might have 20
  • Selective fields: one query needs just names, another needs values and timestamps
GraphQL handles all three naturally. REST would require either over-fetching (return everything) or an increasingly complex parameter system.

Why REST for management and timeseries

Resource management and historical data queries are simple, resource-oriented actions that map directly to HTTP verbs:
  • GET /api/v1/sites/ to list sites
  • POST /api/v1/sites/ to create a site
  • POST /api/v1/sites/{id}/timeseries to query historical timeseries data
GraphQL adds unnecessary ceremony for these straightforward operations. REST’s query parameters are a natural fit for time-range queries, and its HTTP semantics map cleanly to resource CRUD.

Competitor approaches

CompanyArchitectureLimitation
MappedGraphQL onlyNo writes or control
WillowREST onlyPoor composability, multi-call queries
CogniteREST + GraphQLGeneric industrial, no building semantics
DataGridConversational AINo deterministic queries
Tacit combines the right protocol for each concern with building-specific semantics baked in.

Next steps

Quickstart

See the API in action.

GraphQL API

Start querying building data.