Marc,
seems we're finally back at API discussion. :-)
> > The other part of the discussion was about generic vs. specialized
> clients. Jan wants to do spezialized clients, i. e. a client that know
> where to find such links (besides in the entity aka document itself)
> and possibly the role names of the links, while my idea is to have a
> generic client that can be scripted from outside, so the script
> provides the information what role's link is of next interest (like
> "genericClient.invoke("roleName");").
> > I'm curious how an API like that would work in practice. E.g. how would
> > the genericClient find the URI corresponding to "roleName" ? How would
> > the generic client determine the HTTP method to use and what media type
> > to send in its requests (where appropriate).
As you see in the example, the caller of the client is providing the name of
the role of interest.
The client has to sources where it is searching for links with that role
name: First, as I finally agreed ;-), it can check the "Link" header, is the
names of the roles are provided there in the rel attribute (e. g. Link:
<compact.css>; rel="tole"; title="compact"). Second, it can read the
content. As it is a *generic* client is has no idea about what the content
is like, so it obviously has to call a *content* plugin (which anyways is
needed to process the requested entity, just like a browser needs a HTML
plugin, PDF plugin, or SVG plugin). The API of the plugin allows to ask the
plugin for links in the content. For example, a HTML plugin will search for
<A> tags having "rel" equal to the requested role. A XML plugin could search
(using the XSD) for XLink attributes. A JPG plugin will search solely the
"Link" header.
Maybe the misunderstand is: With "generic" I just want to be unaware of the
server's application or framework, not unaware of the MIME type or the http
protocol, just as a browser is unaware of the web shop or bank account it
presents and just is aware of HTML and http.
> I think a useful client-side framework will need to straddle the
> generic vs specialized divide:
>
> - It needs to be able to be used with any link relationship and
> workflow
Exactly. That's why it is impossible to use "any" header, but it must be
exactly the "Link" header -- otherwise the client would be bound to the
particular application, leading to the fact that third party clients not
being able to ever call our service (as they have no plugin to learn about
what fancy header or link location the application author invented).
> - Ideally it would support common formats out-of-the-box
Just like a browser supports HTML, and possible SVG out of the box, the
generic client would come with for example XML and JSON out of the box.
> - It needs to allow specialized extensions that can extract links from
> the appropriate point in a representation.
Just as a browser has plugins for MIME handlers, a generic plugin would just
extend this API to ask the MIME handler for links found in the content.
> - It needs to allow metadata (method, media-type etc) to be provided to
> configure the request
Just as a browser needs to provide Allow:, a generic browser obviously needs
that, too.
> Seems to me that:
>
> Specialized Client == Generic Client + Metadata (script)
Exactly, now you got my point! I want to move the generic stuff out of the
client, so I can have the workflow programmed in any language I like and the
generic client is solely dealing with REST itself! :-)
> The only real difference is the shape of the APIs. I'm not sure what a
> specialized client API for JAX-RS would look like ?
Let me answer the second question first. The JAX-RS generic client already
knows "Resource". So it could have a method called "invoke("role")" which
triggers the search request. It already has an API that declaratively adds
the understanding for MIME types. So that API can get extended by a method
that not just parsed the MIME content, but scans for links
(handler.getLink("role")). The exact syntax cannot be provided here as I had
not the time to learn about the existing client API and implementation,
sorry.
Now the first question. You say that the difference is the shape of the API.
This is not exactly the difference. The difference of my "generic client"
is:
* My generic client is like a browser. It will be not an API for programming
clients. It will be a standalone binary. Just like firefox or ie is not an
API to write browsers, but are browsers themselve.
* My generic client will be embedded in scripts (or possibly, thanks to a
Java API, in Java code). The script allows me to define a workflow. The
workflow might cover lots of different services and can be Groovy, Bash,
Java, whatever. The knowledge about the workflow is solely in the script.
The client has no knowledge about anything but http and REST. The script has
no knowledge about http but solely about the workflow, MIME content and
URIs. Just as I can use cURL in a bash script to upload / download stuff and
cURL doesn't know what actually I'd like to achieve, in the same way will my
generic client be workflow-agnostic and application-agnostic, but still can
drive *any* workflow with *any* server application.
* What Jan (or a JAX-RS client API) is proposing will always lead to a
client that is tightly bound to one particular application. That means, it
is nice to have such an API, but you must write another client for each
application, and the application will work solely with exactly that client.
What if I am using REST because I want anybody call my service with any
client? This would be impossible. But the openness is one of REST's best
attributes. So what will you do if someone has a framework that just cannot
be configured to search for links in any other location but the "Link"
header and entities? That is a valid REST client, but it won't be compatible
with your service. This can be prevented by returning to the core idea of
the web: The client is agnostic of the server and just cares for the http
standard, MIME types, and the URI. The server is agnostic of the client and
just cares for the same. No need to tell either side to use any fancy stuff
besides the "Link" header and the entity. No need to write a particular
client for the service, just as I can use EVERY web page on the web with
EVERY browser.