Skip to content

Server Side Abstractions

Michael Tiller edited this page Jul 31, 2015 · 4 revisions

Introduction

My goal with this session was to discuss some of the abstractions I have chosen in building my framework for simplifying the task of creating hypermedia APIs. In this session, I laid out what I felt were the key abstractions.

Before introducing the abstractions, I identified the goals of my project:

  • Define abstractions such that the API is natively RESTful. By this I mean that an "API" is created in the programming language of the domain objects that itself enforces RESTfulness and self-discovery.
  • Build HTTP transport code on top of the RESTful abstractions once, not for each domain object.
  • Simplify testing by allowing you to test in the programming language of the domain objects and not have to fire up an HTTP server, marshal payloads, unmarshal responses, etc.

In implementation, it is assumed that some "native" domain objects exist. My framework requires that these domain objects be wrapped with a RESTful API in the native language. Then, finally, an HTTP (or other) wrapper can be placed around the native RESTful API in order to (automatically) project the RESTful API into an HTTP based hypermedia API.

My goal is to eventually release this project as open source. If you are interested in getting access to the "work in progress" version, just contact @xogeny.

Abstractions

Resource

Something that we can retrieve. This should provide data, relations and potential actions related to the resource.

Registry

The entry point for the API. This is a singleton that all access should start from. As such, all resources of interest should be somehow "connected" to the registry via a relation.

Context

This represents the identity of the resource (the URI) and the query parameters. Families of resources may be represented by URI templates. But a context can only refer to a single resource. As such, any template parameters must be bound in order to produce a context.

Environment

When a request is made, the resource is identified by the context. But there is other "environmental" information. In an HTTP context, the environment is analogous to headers that are include in the request (since this information is not part of the URI, it is outside the scope of the Context object). A typical example of something that would be part of the Environment would be authentication information.

In my approach, environmental information may get "transformed" by middleware along the way. So the environment isn't strictly limited to the original headers (e.g., in an HTTP context) in a request. Additional information may be injected by middleware.

Relations

This are relations in the same sense that HAL defines relations. The idea here is that relations should either be standard IANA relations or relations defined by the application. When projected onto the API, the internally registered relations will provide a URI that includes machine-readable information about the relation (e.g., as the HAL spec would require).

Actions

Actions were a widely discussed topic at the conference. My feeling is that relations are useful for defining the relationships between resources. But relations say nothing about what you can do with such a resource. In order to support "dumb clients" that can discover information about the API on their own, it is essential (IMO) to provide not only URI templates (for both actions and relations) but also schema information about payloads. Client's should never have to build URIs or guess about query strings or payload parameters.

Actions, like relations, are internally registered. When registered, the actions needs to provide any "parameters" (query string arguments, schema definition) and whether the action is safe and idempotent.

Representations

In a hypermedia context, we have an abstract representation of a resource as having:

  • Parameters (naked data)
  • Relations (connections to other resources)
  • Actions (details about state transitions you can perform on resources)
  • Metadata (description, caching parameters, etc)

In addition, there are at least two other types of representations. One is for redirects and the other is for representing errors.

Clients

We briefly discussed clients. I have been using traverson. I also mentioned hyres, angular-hyres and hyperagent.js as other client libraries that I am familiar with.

One of the recurring themes in this and other sessions was about having a complementary discussion about client-side abstractions. In particular, one thing I pointed out is that traditional hypermedia types drive the client-server interaction to be very "chatty" and to focus on fetching (mostly) one resource at a time. But in order to improve client adoption one thing that clients might find very attractive would be the ability to easily specify more complex queries on the client side, marshal those up as a single request to the server and then have the server traverse the tree of related resources and return specific data that the client asked for. This should, of course, be done using hypermedia semantics which means that the query should be expressed in terms of relationships in the resource tree.