More Thoughts on Links and Operation Subclasses

I’ve been trying to really grok what value Operation subclasses really have. Stock hydra has some base subclasses such as ReplaceResourceOpertion, DeleteResourceOperation, and CreateResourceOperation. Take DeleteResourceOpration for example; there’s really no difference between this:

{
  "@context": "http://www.w3.org/ns/hydra/context.jsonld",
  "@id": "/an-issue",
  "title": "An exemplary issue representation",
  "operations": [
    {
      "@type": "DeleteResourceOperation",
      "method": "DELETE"
    }
  ]
}

And this:

{
  "@context": "http://www.w3.org/ns/hydra/context.jsonld",
  "@id": "/an-issue",
  "title": "An exemplary issue representation",
  "operations": [
    {
      "@type": "Operation",
      "method": "DELETE"
    }
  ]
}

In either case, the client is still going to issue an HTTP DELETE request. The function of the Hyrda operation is implied by the HTTP method that is specified. CreateResourceOperation is also confusing. A new resource could be created via PUT or POST. The intent of POST is not always create. In some of my applications, I’m using POST in a fire and forget model and using a 202 (Accepted) response to indicate success. The resource is receiving events may affect another resource rather that modifying the requested resource via CRUD actions. While yes, I subclass Operation and create my own “FireAndForgetOperation” class. However, the client doesn’t need to know anything about how my server is going to process the message. The POST request may result in a creating a new resource, updating several others, or it may even take a few days to process. The client only needs to know how to format the request (i.e. hydra:expects and hydra:supportedProperties) and how to send the message (hydra:method). With that said, I’m trying to determine if there’s value in having types at that point? There's not much to be gained by everyone inventing their own Operation types.

I've said this before, but the Operation's type feels a lot like Link relations rel attribute. In Hydra, we seem to be using @type to indicate the function of the Operation. Arguably, Link relations do the same thing with the rel attribute with the addition of a set of standard, relatively well-understood relation types. Assuming that the intent of Operation subclasses is similar to Link relation types, I can see Hydra both creating some standard Operation types for common types and potentially incorporating some IANA Link relation types. But this is where things get funky: practically all Link relation types are intended for GET requests. JSON Schema is using Link relations on non-idempotent links, but there’s really not any link relation that I’m aware of that functions with anything other than an HTTP GET. 

And this where things get a little more awkward for me. If we’re talking about a search use case, we could potentially express it with an IriTemplate:

{
  "@context": "http://www.w3.org/ns/hydra/context.jsonld",
   "@type": "IriTemplate",
  "template": "http://api.example.com/issues{?query}",
  "mappings": [
    {
      "@type": "IriTemplateMapping",
      "variable": "query",
      "property": "#SearchCriteria",
      "required": true
    }
  ]
}

But we might also be able to express it as:

{
  "@context": "http://www.w3.org/ns/hydra/context.jsonld",
  "@id": "/issues",
  "title": "Reads a Resource",
  "operations": [
    {
      "@type": "ReadResourceOperation",
      "method": "GET",
      "expects" : "#SearchCriteria"
    }
  ]
}

Ignore the fact for a moment that unlike JSON Schema’s Hyper Schema or Collection+JSON, Hyrda does not specify that we should use the mappings as URL query parameters rather than as a new JSON-LD structure. Something like a search is typically done using GET and could be expressed via an IriTemplate or Operation. Right now, a Link or TemplatedLink feels like an Operation with a method property of GET, yet Hyrda is treating read controls very differently than other type of links or operations. 

Lastly, I think we also need to add two new properties to in order to indicate the media type that should be sent to the server and another that hints at what might be returned from the request. For example:

{
  "@context": "http://www.w3.org/ns/hydra/context.jsonld",
  "@id": "/an-issue",
  "title": "An exemplary issue representation",
  "operations": [
    {
      "@type": "Operation",
      "method": "POST"
      "enctype" : "application/x-www-form-urlencoded",
      “mediaType" : "application/pdf"
      ...
    }
  ]
}

The enctype informs the client as to how to format the request message while mediaType indicates the format that the server may return. If not specified, the value should be application/ld+json if not specified. The mediaType property is more coarse grained than the current hyrda:returns property. in that we’re asserting that the response mediaType might be something other than JSON-LD.

Without these properties, it’s very difficult to work with existing content on the web, whether it be images, PDFs, or other formats such a Atom, HAL+JSON, etc. and even plain old JSON or XML. JSON-LD is awesome, but it’s not the only format on the web. While yes, some of these formats may not fit the Hydra/JSON-LD model, but these formats are in use today. For example, if my App is looking to see what the last 5 commits were on a GitHub project, I need to be able to format a GET request with the required URL parameters. I’m also going to be getting back JSON, not JSON-LD. Now I’m not suggesting that Hydra go all out an support translating JSON data into JSON-LD. No, that’s up to the client application. However, Hydra should be able to properly instruct a client to properly format a application/x-www-form-urlencoded request and indicate that the response may not be a JSON-LD format. 

This is also where I really start to get hanky about hydra:returns and hyrdra:statusCodes. Clients really need to get into the habit of reacting to responses and sensing content via Content-Type and Link headers rather than having a preconceived expectation at build time about what they might get back. Perhaps abandoning the properties isn’t the right solution and perhaps it could be resolved through a Hydra client API. As it stands, these Hydra properties tee up client generators that would be a lot of like what tools like WADL, Swagger, etc. do now. 

We need to make sure that Hydra can accommodate existing media types and even link relations to a certain degree. These formats and conventions exist now and applications and APIs are using them today. I’d really like to see Hydra accommodate them in some capacity. 


Ryan-

Received on Saturday, 25 January 2014 15:58:39 UTC