Skip to content

Instantly share code, notes, and snippets.

@ap
Created August 13, 2022 18:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ap/325e44a3bd094629943586e922af780f to your computer and use it in GitHub Desktop.
Save ap/325e44a3bd094629943586e922af780f to your computer and use it in GitHub Desktop.
Re: RFC: Restful Secondary Key API

Theory asks:

In any event, as far as I can tell this is a unique design, so maybe it’s too weird or not properly RESTful? Would love to know of any other patterns designed to solve the problem of supporting arbitrarily-named secondary unique keys. What do you think?

Not that unique. 🙂 And it really has nothing to do with representational state transfer.

This is purely URL design (i.e. purely a server-side concern). So on that note, let’s take a look at the good RFC:

Aside from dot-segments in hierarchical paths, a path segment is considered opaque by the generic syntax. URI-producing applications often use the reserved characters allowed in a segment to delimit scheme-specific or dereference-handler-specific subcomponents. For example, the semicolon (";") and equals ("=") reserved characters are often used to delimit parameters and parameter values applicable to that segment. The comma (",") reserved character is often used for similar purposes. For example, one URI producer might use a segment such as "name;v=1.1" to indicate a reference to version 1.1 of "name", whereas another might use a segment such as "name,1.1" to indicate the same. Parameter types may be defined by scheme-specific semantics, but in most cases the syntax of a parameter is specific to the implementation of the URI's dereferencing algorithm.

So the premise of your design is sound – sound enough, in fact, to show up all the way back in the RFC. 🙂

I would just have used different syntax to match RFC-suggested convention, namely /users/;username={username}.

Note that the parametrization this section talks about is “applicable to that segment”, which is to say that if you want, it naturally expands to support, in your example, things like /users/;username={username}/profile.

@theory
Copy link

theory commented Aug 15, 2022

Oh very nice, appreciate the pointer! I alway know I can count on you to have a solid response to this sort of question.

I can think of two reasons to prefer /users/username:{username}, however:

  1. This API requires that there be only one value, so there's no need for a ; to demarcate multiple fields
  2. I find the use of the : to create a nice aesthetic variation from the search interface, which uses the equal sign. IOW, /users/username={username} is just a little too similar to /users?username={username}, which is the search endpoint for my API. The colon lets the user know that there's something slightly different going on, since it's not used in the search syntax.

And yeah, the ability to return something like /users/username={username}/profile was one of the ideas I had at the back of my mind.

Since I made that post, I've changed things slightly to:

  1. Return a 308 status to indicate that it isn't the canonical URL for the user
  2. Add a Location header with the canonical URL for the resource (/users/{uid})

Appreciate your response and validation of the underlying idea! Now to find out of my co-workers convince me to use gRPC/Protobuf, instead.

@ap
Copy link
Author

ap commented Aug 15, 2022

1. This API requires that there be only one value, so there's no need for a ; to demarcate multiple fields

It plays the role of not just the & in the query parameters but also the ?. It’s a marker that the segment is parametrized in some way in the first place. Without any ; present, the = is just part of the name of the path segment, similar to a query without a ?.

2. I find the use of the : to create a nice aesthetic variation from the search interface, which uses the equal sign. IOW, /users/username={username} is just a little too similar to /users?username={username}

Exactly, the equals sign needs the semicolon in order to work.

I can think of two reasons to prefer /users/username:{username}

One more reason not to which I’ve not brought up so far is that among reserved characters, : is in the gen-delims set whereas ; and = (and also ,) are only in the sub-delims. One of the consequences section 3.3 on paths cites is

In addition, a URI reference (Section 4.1) may be a relative-path reference, in which case the first path segment cannot contain a colon (":") character.

Admittedly it’s more of a congealed gut sense over time since I no longer remember the individual cases, but occasionally hitting cases where colons had to be encoded or cases where URI code just chose to encode most colons (which per section 2.2 on reserved characters is a perfectly reasonable way to deal with the gen-delims set) has left me with a vague iffiness about the colon as syntax in URLs. So I try to avoid it if I can.

Since I made that post, I've changed things slightly to: […]

Very nice, those are great changes.

@theory
Copy link

theory commented Aug 15, 2022

I think I'm okay with those trade-offs, but will check to make sure my code handles the encoding of the :.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment