Skip to main content

Declarative APIs pt.1: Identifiers + SQL

· 2 min read
austin ce

Gwen Shapira of The Nile recently shared some interesting discussions on what people use for the IDs in their systems. Most advocate for (or against at all costs!) one format or another, citing the technical pains and trade-offs.

For control planes (and cloud service APIs, more generally), IDs are how you address the API objects in the system. In healthy systems, users are creating and interacting with objects all the time.

I'm not here to argue for one format or another. Instead, I'd like to show why, whatever format you pick for your control plane IDs, they should be provided by your users. Without that, the APIs can't be declarative and become much more difficult to adopt into workflows.

So let's take the long-time declarative API poster-child, the one, the only: SQL!

What if SQL identifiers were controlled by the system instead of the user?

CREATE TABLE Puppies (
ID SERIAL,
Name TEXT,
Breed TEXT
);

-- OK, now let's add some puppies!
-- But first, we need the Table ID in order to address it.
INSERT INTO (
SELECT tableid
FROM `pg_catalog.pg_tables`
WHERE tablename = 'Puppies'
)
(Name, Breed)
VALUES ('Moody', 'Chihuahua Mix');

This isn't valid SQL, but hope you get my point. Referencing objects you create becomes much more difficult when you need to query for their identifiers.

To express similar API calls from a CLI, they are just as inconvenient as the above SQL, but sadly more familiar.

api create table Puppies # ...
api insert-into \
--table=$(api get table-id --name=Puppies | jq -r '.[0].id') \
--data='{"name": "Moody", "breed": "Chihuahua Mix"}'

If we want using our REST APIs to be as easy as submitting a SQL statement, we must allow people to name their own identifiers.

SQL's execution model is simpler than a control plane's. SQL executes sequentially, whereas control plane APIs are increasingly asynchronous. Missing references could mean the object just doesn't exist yet, but will in a few seconds. If the system doesn't account for this burden, users must. That's up next.