Syscat HTTP API - conceptual overview (Wikipages)

I wanted a system flexible enough to represent whatever things happen to be (wanted) in an IT environment, and whatever kinds of interconnections happen to exist (or be wanted) between them. I also found it valuable to separate a thing's identity from its relationships to the things around it - so instead of having "vendors" and "customers" you have people and organisations that can have "vendor" and/or "customer" relationships between them, allowing for one organisation to be both vendor and supplier to another.

I also wanted something with an API that was easy to build automation on. This meant it needed a predictable, regular form with the fewest feasible number of exceptions.

All these factors led to a system built on the concepts described in this document.

Note that I gloss right over most of the technical details here; those are covered in other documents.

Resources and resourcetypes

The "things."

If you're familiar with object-oriented programming, these map neatly enough onto classes and instances.

Resourcetypes are the abstract idea of a "type of thing," including its attributes. A person might have a display-name, year of birth, and a field for recording notes about them; a book might have an ISBN and a blurb; Wikipages like this one have Title and Text, where the Title enables you to give it a friendlier, more readable title than the URI constraints allow (like non-ASCII characters). Each attribute also has a type, with the default being free text.

Resources are concrete instances of a type - a specific person, or a specific book. A resource is identified by a combination of its resourcetype and its unique (within its type) identifier, given in the form of an HTTP-safe URI: /People/John_McCarthy, or /Books/Practical_Common_Lisp, or /Wikipages/Syscat_HTTP_API_-_conceptual_overview (this page).

Taking inspiration from the REST architecture, I use a convention of plural names for resourcetypes, with CamelCase where names are composed of two or more words.

UIDs are sanitised when resources are created, and the server includes the sanitised UID in its response. It actually returns the full identifying path, as per the examples earlier in this section.

Resource versions

Each time you update the user-definable attributes of a resource, the server creates a new version of its attribute-set, which includes an optional version comment. You can query the server for the list of versions of a resource, fetch the contents of a given version, and set the "current" version to be any of those. This enables you to roll back and forward between versions.

Relationships

As you'd expect, these are named relationships between things. Note that they're directional - each relationship is from one specific resource, to another specific resource. In most cases, one relationship is complementary to another, reflecting how things work in the real world.

In Syscat, a relationship has a few attributes:

As a naming convention, I went with SCREAMING_SNAKE_CASE - apart from it having the single coolest name in the history of case-names, it makes it nice and easy to distinguish the various parts of a URI path in Syscat.

Thus, a complementary pair of paths might look like this:

In case you're wondering whether you can chain any number of these identifiers and relationships together, the answer is yes... subject to limits on URL length. So don't bet on getting past 1024 bytes, including the base URL.

Important note about relationships

As I telegraphed in the opening paragraph, Syscat was designed for flexibility in describing relationships, to cover two important cases:

Dependent resources

Some things exist only in the context of some other things, e.g. chapters of a book.

These are just like the resources described earlier, except that their resourcetype has the dependent attribute set to true. To complete the mechanism, there also needs to be at least one relationship to a dependent resourcetype, which also has dependent set to true.

For practical reasons, each resource must have exactly one path that uniquely identifies it, so each dependent resource must have exactly one parent resource. This is called its canonical path. It can have any number of other types of relationships to and from other resources, of course.

These can be dependent on other dependent resources, with no inherent limits beyond those imposed on URLs - you can chain them just as deeply as you need to.

To keep with the book-and-chapter theme, the path for a chapter might look like this: /Books/Practical_Common_Lisp/CONTAINS/Chapters/4_Syntax_and_Semantics.

The astute reader will notice that this is no different to the casual reader from /People/Me/IS_READING/Chapters/4_Syntax_and_Semantics. For this reason, each time you GET a resource, its list of attributes includes the canonical path, so that you can positively identify it without difficulty.

Schemas

The set of resourcetypes and relationships defined in the Syscat server is called a schema, which is a direct reference to the relational/SQL-style schemas that partially inspired this system.

These are versioned, too, and you can roll forward and back in the same way as for resources. Unlike relational databases, though, changing the schema does not change the data already present in the database. This minimises the risk involved in testing new definitions, though I'll admit that renaming an attribute is a royal pain in the neck.

Definitions are added to the schema by uploading a JSON document, which means you can add your own resourcetypes and relationships, and even add attributes to existing resourcetypes. This enables you to seamlessly extend the system to cover your own needs and use-cases, without having to negotiate with a vendor and wait for them to release it. Because you do this using the same inbuilt mechanism as the pre-baked stuff, it's even vendor-supported!