Writing a client for a RESTful (hypermedia) API

2020-02-19 23:11发布

问题:

I've been reading up on 'real' RESTful APIs for a few days now, and I think I'm near to groking what it's about.

But one of the things that I stumble on is that I can't even begin to imagine how one would write a client for a 'real' hypermedia API:

  1. Most of the examples I've read talk about browsers and spiders, but that's not especially helpful: one is human-directed and 'intelligent', the other is dumb and 'random'. As it stands, I kind of get the impression that you'd need to learn AI to get a client working.

  2. One thing that isn't clear to me is how the client knows which verb to use on any given link? Is that implicit in the 'rel' type of the uri? The alternative (reading here) seems to be using xhtml and having a client which can parse and post forms.

  3. How likely is it that a link will change, but not the route to the link? In most examples you see around, the route and the link are the same:

eg. if I want to set up a client which will bring me back the list of cakes from Toni's Cake Shop:

http://tonis.com
{ link: { type : "cakes" ; uri : "http://tonis.com/cakes" } }

What happens when Toni's becomes Toni's Food Shop, and the link becomes http://tonis.com/desserts/cakes?

Do we keep the initial cakes link at the root, for reverse-compatibility? And if not, how do we do a 'redirect' for the poor little agent who has been told "go to root, look for cakes"?

What am I missing?

回答1:

@Benjol

You must avoid to program clients against particular URI's. When you describe a link main importance has it's meaning and not URI itself. You can change the URI any time, though this shouldn't break your client.

I'd change your example this way:

{"link": {
  "rel":   "collection http://relations.your-service.com/cakes",
  "href":  "http://tonis.com/cakes",
  "title": "List of cakes",
  "type":  "application/vnd.yourformat+json"
}}

if there is a client which consumes your service, it needs to understand:

  • link structure itself
  • link relationships(in this case "collection" which is RFC and "http://relations.your-service.com/cakes" which is your domain specific link relation)

In this case client can just dereference address specified by "href" attribute and display list of cakes. Later, if you change the cake list provider URI client will continue to work, this implies that client still understands semantics of your media type.

P.S.

  • See registered link relation attributes: http://www.iana.org/assignments/link-relations/link-relations.xml
  • Web Linking RFC: http://tools.ietf.org/html/rfc5988


回答2:

Ok, I'm not a REST expert either, I've been reading much related stuff lately, so what I'm going to write is not my experience or opinion but rather a summary of what I read, especially, the REST In Practice book.

First of all, you can't escape from having some initial agreement between client and server, the goal of REST is to make them agree on the very minimum of things which are relevant to both of them and let each party care about their own stuff themselves. E.g., client should not care about links layout or how the data is stored on server, and server should not care about a client's state. What they agree on in advance (i.e. before the interaction begins) is what aforementioned book's authors call "Domain Application Protocol" (DAP).

The important thing about DAP is that it's stateful, even though HTTP itself is not (since any client-service interaction has state, at least, begin and end). This state can be described in terms of "What a client can/may/is expected to do next": "I've started using the service, what now? Ok, I can search items. Search this item, what's next? Ok, I can order this and that... etc"

The definition of Hypermedia content-type is being able to handle both data exchange and interaction state. As I already mentioned, state is described in terms of possible actions, and as comes from "Resource" in REST, all actions are described in terms of accessible resources. I guess, you have seen the acronym "HATEOAS (Hypermedia as the engine of application state), so that's what it apparently means.

So, to interact with the service, a client uses a hypermedia format they both understand, which can be standard, homegrown or a mixture of those (e.g. XML/XHTML-based). In addition to that, they must also share the protocol, which is most likely HTTP, but since some details are omitted from the standard, there must be some idioms of its usage, like "Use POST to create a resource and PUT to update". Also, such protocol would include the entry points of the service (again, in terms of accessible resources).

Those three aspects fully define the domain protocol. In particular, a client is not supposed to know any internal links before it starts using the service or remember them after the interaction completes. As a result, any changes in the internal navigation, like renaming /cakes to /f5d96b5c will not affect the client as soon as it adhere the initial agreement and enters the shop through the front door.