The four guiding principles of Uniform Interface are:
_Identification of resources_
Individual resources are identified in requests, for example using URIs in web-based REST systems. The resources themselves are conceptually separate from the representations that are returned to the client. For example, the server does not send its database, but rather, perhaps, some HTML, XML or JSON that represents some database records expressed, for instance, in Swahili and encoded in UTF-8, depending on the details of the request and the server implementation.
_Manipulation of resources through these representations_
When a client holds a representation of a resource, including any metadata attached, it has enough information to modify or delete the resource on the server should it have permission to do so.
_Self-descriptive messages_
Each message includes enough information to describe how to process the message. For example, which parser to invoke may be specified by an Internet media type (previously known as a MIME type). Responses also explicitly indicate their cacheability.
_Hypermedia as the engine of application state (A.K.A. HATEOAS)_
Clients make state transitions only through actions that are dynamically identified within hypermedia by the server (e.g., by hyperlinks within hypertext). Except for simple fixed entry points to the application, a client does not assume that any particular action is available for any particular resources beyond those described in representations previously received from the server.
Code on demand (optional)Servers can temporarily extend or customize the functionality of a client by the transfer of executable code. Examples of this may include compiled components such as Java applets and client-side scripts such as JavaScript. "Code on demand" is the only optional constraint of the REST architecture.
I'm not sure I understand what you mean by 'architecture ... for a web browser client'.
We normally think of our applications as smaller processes that transform data ... Small tools that do one thing well and only one thing
So basically, the web services are just end points that can return data or process data for us. The front end clients only deal with presenting that information in whatever way it needs to, without depending on the end point for anything more than the data
I'm not sure if it's an answer or even on topic so my apologies if it isn't.
I think perhaps you're trying to wrap your head around how REST architectures often want to treat REST messages as resources or collections of data you can manipulate.
So given an architecture which consists of interactors which can be invoked with an input boundary and receives output boundaries as a ui plugin would typically do. And these interactors would in turn use gateway boundaries to fetch and operate on entities hydrated with a persistence plugin.
Then I tried to do the following once:
client side:
AngularJS > Interactors.js > Gateways.js + REST client
server side:
Grails > Interactors > Gateways + GORM
Where of course the Javascript REST client would invoke Grails REST services.
This pretty much failed for me because interactors on both sides had to communicate things like input validation errors up the stack.
Which in this case would have to pass through the gateway boundary on the client side. And I never felt like this was a good fit. I felt like the gateway boundary suddenly had to deal with concepts it had no business with.
So I changed it up a bit to this:
client side:
AngularJS > Interactors.js + REST client
At some point I reasoned that REST is simply my transport protocol and I wasn't interested in sending persistence related messages but usecase related messages.
Given I at first crossed a boundary which put me in a different context the messages I was getting from the server didn't make any sense for that context. I think this may not be very RESTy.
In retrospect I could instead have eliminated the interactors on the server side to allow more RESTful usage patterns but I don't see me do that easily.
It rather fits the resource oriented 'Stereotypical Architecture' that is very good explained here: http://cqrs.wordpress.com (which is a must-read anyway).
Why not? I'd be interested in what makes you think it'd be hard. I can imagine like i mentioned above that could be for security reasons I guess? .. Same here, take a look at pouchdb ! ;
Why not? I'd be interested in what makes you think it'd be hard. I can imagine like i mentioned above that could be for security reasons I guess? .. Same here, take a look at pouchdb ! ;
I don't think it would be hard. I think it would push business logic to the client while I want the server to retain final authority. Thus the server must know about the usecases and must have a way to communicate contextual issues which are larger than the scope of a single resource.
At least with my current understanding I feel stuck going down that road.
However if I let go of my desire to have the server control everything then I think I'd have no immediate issue with it and something like pouchdb would be an option.
It might even be fun as I'd be able to write more of the app in javascript.
Sebastian, so are you saying the controller is really the "boundary" in this scenario?
"/search"(controller: "search", action: "list")
grails-app/controllers/myapp/SearchController.groovy
class SearchController {
def list() {
render status:200, text:'search route hit'
}
}
If I compare this to your example code from koa then I think you'll agree I have not done anything more than you did.
But Grails (and other frameworks) made me implement a "controller". Which is why I was saying your function passed to router.get is your WebMVC controller.
router.get('/search', '/search', function *(next){ this.body = "search route hit"; this.statusCode = 200; });
I bring this up because I see no reason to introduce another controller in between the function you passed to router.get or my own SearchController and the interactor.
Especially if you're going to pass HTTP related artifacts to this controller which would then create the true transport agnostic request object.
I would simply implement my SearchController as follows to:
- convert the HTTP params and request locale into a search request object (simple hash table)
- convert the search results into JSON
- convert input constraint violations into JSON and setting the HTTP response status to indicate invalid input was received.
class SearchController {
def searchInteractor
def list() {
searchInteractor(searchRequest, this)
}
def getSearchRequest() {
[q:params.q, locale:request.locale]
}
def ok(results) {
render(results as JSON)
}
def rejected(violations) {
response.status = 412
render(violations as JSON)
}
}
At this point I can implement the searchInteractor function without HTTP.
I guess I'm saying the searchInteractor+searchRequest+searchResult+searchViolations are the boundary.
The SearchController is simply an HTTP/REST transport.
function(SearchRequest, SearchResponseHandler);
class SearchRequest {
String q
Locale locale
}
interface SearchResponseHandler {
void ok(results)
void rejected(violations)
}