puter/doc/planning/alternatives-to-$.md

3.3 KiB

Problem

When sending metadata along with arbitrary JSON objects, a collision of property names may occur. For example, the driver system can't place a "type" property on an arbitrary response coming from a driver because that might also be the name of a property in the response.

Example:

{
    "type": "api:thing",
    "version": "v1.0.0",
    "some": "info"
}

Awful Solution

Reserved words. Drivers need to know their response can't have keys like type or version. If we'd like to add more meta keys in the future we need to verify that no existing drivers use the new key we'd like to reserve. If we have have such features as user-submitted drivers this will be impossibe. A meta key as a single reserved word could work, which is one of the solutions discussed below.

Obvious Solution:

The obvious solution is to return an object with a head property and a body propery:

{
  "head": {
    "type": "api:thing",
    "version": "v1.0.0"
  },
  "body": {
    "some": "info"
  }
}

I don't mind this solution. I've come up with some alternatives though, because this solution has a couple drawbacks:

  • it looks a little verbose
  • it's not backwards-compatible with arbitrary JSON-object responses

Solutions

Dollar-Sign Convention

  • Objects have two classes of keys:
    • "meta" keys begin with "$"
    • other keys must validate against the usual identifier rules: /[A-Za-z_][A-Za-z0-9_]*/
  • The meta key $ indicates the schema or class of the object.
  • Example:
    {
      "$": "api:thing",
      "$version": "v1.0.0",
    
      "some": "info"
    }
    
  • what sucks about it:
    • $ might be surprising or confusing
    • response is a subset of valid JSON keys (those not including $)
  • what's nice about it:
    • backwards-compatible with arbitrary JSON-object responses which don't already use $

Underscore Convention

  • Same as above, but _ instead of $
    {
      "_": "api:thing",
      "_version": "v1.0.0",
    
      "some": "info"
    }
    
  • what sucks about it:
    • _ might be confusing
    • response is a subset of valid JSON keys (those not including _)
  • what's nice about it:
    • _ is conventionally used for private property names, so this might be a little less surprising
    • backwards-compatible with arbitrary JSON-object responses which don't already use _

Nesting Convention, simplified

  • Similar to the "obvious solution" except metadata fields are lifted up a level. It's relatively inconsequential if meta keys have reserved words compared to value keys.
    {
      "type": "api:thing",
      "version": "v1.0.0",
      "value": {
          "some": "info"
      }
    }
    

Modified Dollar/Underscore convention

  • Using _ in this example, but instead of prefixing meta properties they all go under one key.
    {
      "_": {
          "type": "api:thing",
          "version": "v1.0.0"
      },
    
      "some": "info"
    }
    
  • what sucks about it:
    • _ might be confusing
    • response is a subset of valid JSON keys (those not exactly _)
  • what's nice about it:
    • _ is conventionally used for private property names, so this might be a little less surprising
    • backwards-compatible with arbitrary JSON-object responses which don't already use _ as an exact key
    • only one reserved key