Alternative "simple" services implementation

2,569 views
Skip to first unread message

gregmac

unread,
Dec 9, 2011, 11:57:03 AM12/9/11
to servic...@googlegroups.com
Let me start out by saying that I think ServiceStack is a great platform - it is very well put together and is pretty easy to get up and going with.

One thing I haven't totally wrapped my head around is the philosophy that every request is a DTO, and that routes map to DTOs, and that there happen to be services floating around that service the request DTOs. I've seen some discussion related to that topic but it doesn't address everything:
  • First off, NOT every request is a DTO. This is easily seen in the MoviesRest example, where there is an action "ResetMovies". Because of the architecture of SS, you have to post an empty ResetMovies DTO (which is meaningless).. basically the paradigm doesn't make sense for that type of action, at least for me.
  • It's complicated to actually define how a URL maps to code, as you have to define the route (where you may optionally specify HTTP verbs), connect the route to a DTO, and then define a service for the DTO, and finally in that service you have code that handles the request, and can optionally handle it differently (or not at all) based on HTTP verb. 
  • There is no way (that I have seen so far) to distinguish between a parameter passed in the URL and POST/PUT'd as part of the request: If I do a PUT to  /users/123  with the object {id:234,name:Test} what am I doing? Editing user id 123 or 234? Am I trying to change the id from 123 to 234?
So I could go on about that, but my point is not to complain, just to show my motivation.

What I am looking for is a way to very easily connect URLs to services. These may be dealing with DTOs, they may be dealing with actions (such as ResetMovies).

    [GET("users/{userid}")]
    public UsersResult Load(int userid)

    [PUT("users/{userid}")]
    public UsersResult Edit(int userid, Models.User user) 

and so on. 

This is conceptual at this point but the idea is the attributes define the route (you could also do this via regular route definitions, or even by convention via class/method names like ASP MVC), and the URL parameters are always passed to the method as well as the posted model, if any. 

Compare the code required to have a basic service. svc refers to my underlying service layer. 

ServiceStack existing:

    [DataContract]
    public class UserRequest { 
       public int id;
    }
    public class UserService : RestServiceBase<UserRequest> {
        public MyServiceLayer.Service svc { get; set; }
        public override object OnGet(UserRequest user) {
            return svc.LoadUser(user.id);
        }
    }

    .... and elsewhere in global.asax...
    Routes.Add<UserRequest>("/users/{id}", "GET");


Proposed: 

    class UserService : SimpleRestService {    // ?
        public MyServiceLayer.Service svc { get; set; }
        [GET("users/{userid}")]
        public UsersResult Load(int userid) {
           return svc.Load(userid); 
        }
    }


I bolded what is in my opinion the non-boilerplate code. 

I'm willing to put energy into developing this on top of SS, but am I missing something? Is there a reason this is a terrible idea? Am I committing some sin against REST?

I am considering this as an extension on top of SS or an alternative built-in method (depending if it gets accepted into the project), not a total replacement for the existing interface.

Demis Bellot

unread,
Dec 9, 2011, 12:56:40 PM12/9/11
to servic...@googlegroups.com
Hi gregmac,

Thanks for your feedback.

I try to promote a single message-based DTO approach to designing and invoking services. 
There is major usability and re-usability advantages by having every service accept a Request DTO and conversationally returning a Response DTO (with Results and Exceptions in predictable properties). 

This has major ripples through the entire use and design of your services from understanding how each service behaves, usage by your Service Clients, being able to proxy/delegate or drop your Request DTO into a sub-service or MQ for async message processing etc.

Basically leaving everything as 'Message based' is a powerful concept that I will be keeping, as soon as you start to map Web Service Calls to an RPC method signature you are no longer 'sending a Request DTO' to a service, you're instead trying to invoke that particular method signature - it becomes much more tightly coupled and you're ability to evolve that service becomes hindered as any changes on the server effectively means the client needs to change as well and marshaling to a Method signature tends to mean you'll need to have client code-gen in order to provide a typed, succinct API. You'll also need to do this for every service client you want to support (i.e. JSON/XML/JSV/MQ/etc) unlike the elegant approach of the generic Service Clients bundled with ServiceStack.

Code-gen is another one of my major dislikes and IMO should be avoided where possible, it becomes an arthritis in your system and you start to become a slave to your tooling - In my experience code-first produces simpler more elegant and maintainable solutions then code-gen.

So whether you have 0 properties, 1 property or 20 properties they all work the same way and IMO there is not much boilerplate in doing:
public class ResetMovies {} for an empty DTO.

If you prefer the RPC approach for services you should easily be able to implement this in a base-class using your own attributes / conventions where you marshal the Request DTO to your sub class method calls (likely the approach you're thinking about already).
If there is strong demand by others in this group I can include your base class into ServiceStack.ServiceInterface.dll so it's an optional feature they can choose to use or not.
Otherwise of course the other option is to host ServiceStack with MVC or NancyFx and use they're routing system when it makes more sense to.

It's complicated to actually define how a URL maps to code

There are 2 ways to map a Route with your Request DTO it sounds like you would prefer the 2nd option, where the route is more cohesively kept with your Request DTO e.g:

[RestService("/users/{Id}")]
public class Users { ... }

Personally I think the convention of not specifying the Verb means it applies to all HTTP Verbs is an acceptable default convention that's natural to assume.

There is no way (that I have seen so far) to distinguish between a parameter passed in the URL and POST/PUT'd as part of the request:

You can either have 2 Id Properties for cases when you think they will be different (personally I think this is situation should be rare):

[RestService("/users/{ForId}")]
public class Users { int ForId, int Id, ... }

Or alternatively inspect the HttpRequest to determine which Id was passed in the Request Path, i.e:

var httpReq = base.RequestContext.Get<IHttpRequest>();  
httpReq.Path; //httpReq.AbsoluteUri, etc.

There's a couple of things I would do differently, here's my version:

[RestService("/users/{Id}")]
[RestService("/users/{Id}/{Method}")]  /* [DataContract] not needed, Drop Request suffix */ 
public class Users { 
public int Id { get; set; }
public string Method { get; set; }
}

public class UserService : RestServiceBase<Users> {
public MyServiceLayer Svc { get; set; }

public override object OnGet(Users request) {
if (request.Method == "load") 
    return Svc.LoadUser(request.Id)
...
}
}

i.e. I would leave off any 'Request' or 'Dto' suffix on your Request DTO as I like to consider the Request DTO *is* the contract/API for your service and what you should be referring to when you talk about it (i.e. the Service implementation should be remain an implementation issue :)

I am considering this as an extension on top of SS or an alternative built-in method (depending if it gets accepted into the project), not a total replacement for the existing interface.

If you're more comfortable with this approach then I see no harm in developing this even if it's just for yourself (a lot of the features in ServiceStack is to scratch my own itch as well). 
Personally I wont be using this feature since I don't think the boilerplate reduction justifies the added delegation/complexity and less debuggability but if there is a strong demand for this I can include it in the ServiceStack.ServiceInterface project.

Hope this helps clarify some of the philosophy behind ServiceStack.

Cheers,

gregmac

unread,
Dec 11, 2011, 9:10:57 PM12/11/11
to servic...@googlegroups.com
Hi Demis,


On Friday, 9 December 2011 12:56:40 UTC-5, mythz wrote:
I try to promote a single message-based DTO approach to designing and invoking services. 
There is major usability and re-usability advantages by having every service accept a Request DTO and conversationally returning a Response DTO (with Results and Exceptions in predictable properties). 

This has major ripples through the entire use and design of your services from understanding how each service behaves, usage by your Service Clients, being able to proxy/delegate or drop your Request DTO into a sub-service or MQ for async message processing etc.

So what you're saying is that keeping each request as a single DTO simplifies the use of certain patterns on the clients, such as using a queue.  Okay, I will somewhat buy that, but the client still needs to know the URL to send the DTO to..
 

Basically leaving everything as 'Message based' is a powerful concept that I will be keeping, as soon as you start to map Web Service Calls to an RPC method signature you are no longer 'sending a Request DTO' to a service, you're instead trying to invoke that particular method signature - it becomes much more tightly coupled and you're ability to evolve that service becomes hindered as any changes on the server effectively means the client needs to change as well and marshaling to a Method signature tends to mean you'll need to have client code-gen in order to provide a typed, succinct API. You'll also need to do this for every service client you want to support (i.e. JSON/XML/JSV/MQ/etc) unlike the elegant approach of the generic Service Clients bundled with ServiceStack.

I don't understand what you're saying here. What in the SS pattern prevents the client from needing to change if the server changes? As far as I can tell, the client still has to know the URLs, and still has to know the DTO. 

If you change the URL endpoint on the server, the client has to change -- so I'm failing to see why my proposed pattern is any different. In existing SS and what I'm proposing, you can make a change to the server that requires the clients to change, and you can also do some changes that are backwards compatible.




So whether you have 0 properties, 1 property or 20 properties they all work the same way and IMO there is not much boilerplate in doing:
public class ResetMovies {} for an empty DTO.

I don't have any problem with the DTO boilerplate directly. What I find awkward is the connection between the DTOs, services, and routing. I consider the URL and HTTP verb to be effectively one and the same, so what bugs me is the fact that the URL is defined by routing, and the verb is defined by the service code implementation (and also, possibly, the routing). On top of that, the service is not connected directly to the routing -- it's connected implicitly via the DTO.
 

If you prefer the RPC approach for services you should easily be able to implement this in a base-class using your own attributes / conventions where you marshal the Request DTO to your sub class method calls (likely the approach you're thinking about already).

To be clear, I'm not trying to do an RPC approach. I think the difference is that I like to think of the URL first (or in other words, the API of the service). I want direct control of how the URL maps to handler code. With the current SS implementation, I feel like the URL is a by-product of everything else, because it's so convoluted to connect to the handler code. 

To illustrate this, I think: "Ok, I want GET /movies to be a list of all movies, POST /movies to add a new movie, GET /movies/{id} to load a single movie, PUT /movies/{id} to edit that movie, and POST /movies/reset to reset the sample database."  Arguably /movies/reset is RPC-style, but it's inevitable that you'll eventually want to tell the server to do actions, and personally I feel that is still a RESTful way to do it. 

In SS now, I have to now do a second step. For each distinct request, I need to think about what the request DTO is going to be, and then I have to map that DTO to a URL. Then, I have to go back and map each request DTO to the IService that can handle it. 

 
It's complicated to actually define how a URL maps to code

There are 2 ways to map a Route with your Request DTO it sounds like you would prefer the 2nd option, where the route is more cohesively kept with your Request DTO e.g:

[RestService("/users/{Id}")]
public class Users { ... }

Personally I think the convention of not specifying the Verb means it applies to all HTTP Verbs is an acceptable default convention that's natural to assume.

Yeah sorry, I should have pointed this out in my example since it is closer to what I was showing.  I do agree, in this design, not specifying a verb having the meaning of all verbs is very natural. 
 
There is no way (that I have seen so far) to distinguish between a parameter passed in the URL and POST/PUT'd as part of the request:

You can either have 2 Id Properties for cases when you think they will be different (personally I think this is situation should be rare):

[RestService("/users/{ForId}")]
public class Users { int ForId, int Id, ... }
Or alternatively inspect the HttpRequest to determine which Id was passed in the Request Path, i.e:

var httpReq = base.RequestContext.Get<IHttpRequest>();  
httpReq.Path; //httpReq.AbsoluteUri, etc.


In my opinion, both of these methods are total hacks. In the first method, you STILL have the same problem -- what happens when a client specifies ForId as part of the request DTO and the URL? Actually that is a rhetorical question - it doesn't matter, because as a user of servicestack, there is no clear answer. I'd have to read the SS code and/or documentation, or figure it out by trial and error. I am suggesting there is a better API that removes this ambiguity, and makes a natural and supported way to get at these properties.
 
There's a couple of things I would do differently, here's my version:

[RestService("/users/{Id}")]
[RestService("/users/{Id}/{Method}")]  /* [DataContract] not needed, Drop Request suffix */ 
public class Users { 
public int Id { get; set; }
public string Method { get; set; }
}

public class UserService : RestServiceBase<Users> {
public MyServiceLayer Svc { get; set; }

public override object OnGet(Users request) {
if (request.Method == "load") 
    return Svc.LoadUser(request.Id)
...
}
}

I personally don't like this at all. This now looks like RPC: you have a verb in the URL. I know it's somewhat hypocrtical of me to say this after suggesting "/movies/reset", but there is no HTTP verb for "reset all movies", while there is a verb for load (GET). 

I also really don't like having (request.Method == "load") in the service code. It feels to me like the framework only did 80% of the work it should have - it mapped the request object into service code by looking at the URL and mapping parameters, but then it left the final 20% up to the service implementation. It just seems like this is something that the framework should do for you, the actual code a user of the framework should write should be pure service implementation -- leave the mapping of the request to my code up to the framework.


I am considering this as an extension on top of SS or an alternative built-in method (depending if it gets accepted into the project), not a total replacement for the existing interface.

If you're more comfortable with this approach then I see no harm in developing this even if it's just for yourself (a lot of the features in ServiceStack is to scratch my own itch as well). 
Personally I wont be using this feature since I don't think the boilerplate reduction justifies the added delegation/complexity and less debuggability but if there is a strong demand for this I can include it in the ServiceStack.ServiceInterface project.



 
Hope this helps clarify some of the philosophy behind ServiceStack.


It does somewhat, but I don't really get the full motivation yet. Since no matter what, you're still tied to the URL, any attempt to abstract that away actually seems counter-intuitive. 

In the end, I'm just looking to simplify mapping between URLs and service code. What I was hoping to get out of this thread is an understanding of why having a DTO is beneficial, but so far I don't get it. You briefly mentioned using queues, and I think were hinting at abstracting away the implementation (which I guess means the URLs the client points at?) but I fail to understand how it's possible to have the client ignore the URL, and why knowing the URL (and even having parameters in it) cause any problems on either the client or server. Is there an example somewhere you can point me at, where it's clear that the single request DTO is beneficial, and it's not possible to do it using my proposed code? 

Am I still completely missing something here?

Thanks, 
Greg


Demis Bellot

unread,
Dec 12, 2011, 1:25:01 AM12/12/11
to servic...@googlegroups.com
Firstly I want to point out the patterns and core ideas ServiceStack is based around and tries to promote - they are all short but highly recommended reading.
Here are the very few patterns I follow and find fundamentally important when developing web services, which are strangley enough also available on the MSDN website but for whatever other reason is discouraged by WCF:

  - Remote Facade Pattern - Promoting the design of coarse grain and batchful interfaces whenever you communicate across process boundaries.

  - DTO pattern - Special purpose POCOs that define your web services payloads.
  
  - Service Gateway pattern - To encapsulate your client and server communications.

I also believe these patterns promote 'web service development best practices' that better lend themselves in designing SOA systems as it leads to fewer, less client-specific and more re-usable services. I've created a small gist to show the contrast between the RPC methods that I believe WCF encourages and the equivalent services I hope to encourage with ServiceStack:

The above gist also shows you how you can easily add extra service functionality to the Request DTO and data to the Response DTO in a way that doesn't effect old/existing clients as the extra functionality/data just gets ignored by unaware clients. The JSON and JSV endpoints and serializers are extremely resilient and can withstand some extreme versionability of your services without error.

The above patterns (and many more) are discussed in detail in Martin Fowlers excellent Patterns of Enterprise Application Architecture.
 
So what you're saying is that keeping each request as a single DTO simplifies the use of certain patterns on the clients, such as using a queue.  Okay, I will somewhat buy that, but the client still needs to know the URL to send the DTO to..

ServiceStack automatically exposes Sync and Async Urls for each of your web services (see: "The different ways of calling your Web Service" in http://www.servicestack.net/ServiceStack.Hello/)
This lets you provide a base url into any ServiceClient which lets you call each web service. Here's a Unit/Integration Test example that allows the same unit test to be executed by all ServiceClients using the same Base Url. No custom routes were needed:


This is effectively impossible to achieve if you had used code-gen clients, which lets you bind to an implementation-free IServiceClient that allows you to switch formats (ServiceClients) at anytime without any rewrites required.

The custom routes are there if you want to provide REST-ful canonical urls for all your services if you prefer - though it's entirely optional and not needed by default.

I don't have any problem with the DTO boilerplate directly. What I find awkward is the connection between the DTOs, services, and routing. I consider the URL and HTTP verb to be effectively one and the same, so what bugs me is the fact that the URL is defined by routing, and the verb is defined by the service code implementation (and also, possibly, the routing). On top of that, the service is not connected directly to the routing -- it's connected implicitly via the DTO.

Yes this is the ServiceStack idiom where the Request DTO is your service - it defines the contract and is all you need to identify and invoke it. So in ServiceStack the Request DTO == Your service, which is why I suggest you make it a first-class concept and you drop any 'Request' suffix you might have as the Request DTO is your code-first contract and everything else hangs off it.

I personally don't like this at all. This now looks like RPC: you have a verb in the URL.

You may not like it but it's extremely intuitive as to which method gets invoked via each HTTP Verb. The only difference between inheriting from ServiceBase and RestServiceBase is that ServiceBase.Run() gets invoked for every HTTP verb on any endpoint with any format, etc whilst RestServiceBase.OnGet()/OnPost() etc will execute different methods based on the HTTP Verb which is ultimately what you want when you're implementing a REST-ful api.

I also really don't like having (request.Method == "load") in the service code. It feels to me like the framework only did 80% of the work it should have

Up to this point is where ServiceStack marshals the request into a C# Request DTO (via any endpoint, format or calling convention) is the bottom most point where it works naturally as expected, any further then it starts to become opinionated, you lose debuggability and "magic behaviour" starts to occur. Like I've articulated I dislike marshalling to a RPC method signature as I think it promotes the wrong service API design and implementation also once you lose the Request DTO you start to lose your ability to cleanly defer, proxy or cache the request.

It does somewhat, but I don't really get the full motivation yet. Since no matter what, you're still tied to the URL, any attempt to abstract that away actually seems counter-intuitive. 

You're not tied to the url if you use the auto generated routes (i.e. you only need supply the base url). If you're just doing a client/server app where you provide an .NET client gateway that wraps your services i.e. the client never sees the custom url routes then I don't believe you should have any as it just adds an extra layer of un necessary 'industrial knowledge' i.e. more friction / work that needs to be done and that can get out of sync with your services.

In the end, I'm just looking to simplify mapping between URLs and service code.

You should be able to provide the custom Url routing using the attributes and conventions you prefer with your own base class. And like I said earlier if there is strong demand for this I can include as an opt-in, in the framework.
By letting you do it (and not the framework) you get debuggability on the area which I believe will prove problematic and other users that don't like this indirection (i.e. me) needn't suffer the additional perf overhead for a feature they don't use.

What I was hoping to get out of this thread is an understanding of why having a DTO is beneficial, but so far I don't get it. You briefly mentioned using queues, and I think were hinting at abstracting away the implementation (which I guess means the URLs the client points at?) but I fail to understand how it's possible to have the client ignore the URL, and why knowing the URL (and even having parameters in it) cause any problems on either the client or server. Is there an example somewhere you can point me at, where it's clear that the single request DTO is beneficial, and it's not possible to do it using my proposed code? 

All the HTTP Service Clients in ServiceStack:
including the non-HTTP Messaging, Redis MQ and RCON clients can invoke a service with just the Request DTO, it can do so providing a typed API without any code-gen simply because everything hangs off the Request DTO which maps 1:1 with your service. For better or worse the Request DTO is your service interface you will have a lot less time fighting the framework if you follow this single fundamental convention. 

 I fail to understand how it's possible to have the client ignore the URL

All HTTP Service Clients use the auto provided urls as documented in ServiceStack.Hello to invoke any of your services with just your services BaseUri as seen in Integration and Unit test examples.

You can defer the execution of your service for an instant response time and added reliability/durability by dropping it in a MQ like:

using (var producer = MessageFactory.CreateMessageProducer()) {
producer.Publish(request);
}

So far the Messaging Service API in ServiceStack has an InMemory, Redis-backed MQ and TCP/RCON implementations with a very extensible interfaces so you can provide your own MQ adapters.

In order to archive, log or reconstruct the request for later playback you only need to serialize (and playback) the Request DTO - this is impossible to do elegantly if you mapped to an RPC method signature. 

Likewise to delegate/proxy the request to a Sub System (e.g. Master>Shards) you could easily do it with something like: 

public override object Run(Users request) {
var shardClient = this.ShardClients[request.UserId % ShardsCount];
return shardClient.Send<UsersResponse>(request);
}

Basically ServiceStacks 'message-based' approach allows you to solve many high-level messaging integration patterns more elegantly than an RPC approach. 
It increases productivity since there is no code-gen, increases the re-usability and versionability of your services and the added boiler plate should really be inconsequential since you should have less but more coarse-grained/batchful services.

Hope this helps explain the philosophy behind ServiceStack further :)

Cheers,

M. David Peterson

unread,
Dec 14, 2011, 11:09:34 PM12/14/11
to servic...@googlegroups.com
On Fri, Dec 9, 2011 at 9:56 AM, Demis Bellot <demis....@gmail.com> wrote:
Personally I think the convention of not specifying the Verb means it applies to all HTTP Verbs is an acceptable default convention that's natural to assume.

Not to mention absolutely critical to the foundation of a REST-based architecture.  One of primary reasons I chose to fully embrace ServiceStack 2+ years ago as a core part of our architecture was because Demis was adamant about keeping the library firmly founded on a true REST foundation where everything is a resource represented by a distinct URI endpoint in which CRUD operations are specified using the built-in architecture of the web in HTTP(S) verbs. 

If you start thinking of DTO's in the same sense that you think of any other resource on the web, placing the focus on Creating, Reading, Updating, and Deleting that resource via passing (potentially) modified copies of that same resource between client and server (and therefore fully embracing the stateless nature of the URI-centric HTTP architecture) it then becomes a lot easier to either fully embrace (or fully reject) the REST-based DTO-centric focus of ServiceStack. That doesn't mean that choosing not to embrace the ServiceStack approach is absolutely wrong. It just means that your application needs are likely not a good fit with the ServiceStack approach.

--
/M:D

M. David Peterson
Co-Founder & Chief Architect, 3rd&Urban, LLC
Email: m.d...@3rdandUrban.com
Voice: (801) 742-1064
http://amp.fm | http://mdavidpeterson.com

Ethan Brown

unread,
Dec 15, 2011, 1:09:37 PM12/15/11
to servic...@googlegroups.com
Greg - 

As an addendum to everything that's been said, REST purists (by way of Roy Fielding) will promote HATEOAS, which is essentially an additional layer of indirection between the entry point of your API, and the actual resource URIs.  So to your point about mapping to URIs, clients *can* be insulated from actual Resource URIs if you take a HATEOAS style approach.  

Unfortunately, there isn't great tooling for that architectural style, it adds an additional complexity burden on the client, potentially adds extra chattiness (if you don't implement caching semantics properly), and it isn't something you'll see a lot of in the wild for real world examples, etc.  See this SO search for some examples and some of +s / -s to HATEOAS (including a few examples like Suns Cloud API):

Demis isn't a fan and AFAIK, SS doesn't support this out of the box (please correct me if I'm wrong Demis!)
You could roll your own for basic scenarios, and you could probably find a reasonable way to do this generically since services are registered in the top level IoC container, but only your environment will determine if there's any real value. YAGNI and all that... 

You might also find this interesting as it talks about HATEOAS wrt versioning:

There is this Ruby / Java / .NET client that does HATEOAS (not to steal any thunder away from SS!).  I've never used it, but if that's a better fit for what you're looking to do, have a look.


-e

Demis Bellot

unread,
Dec 15, 2011, 3:52:58 PM12/15/11
to servic...@googlegroups.com
Right, 

I'm not a fan of HATEOS which is basically just an imposed set of restrictions forcing you to be more abstract and do more work than you otherwise would, it also promotes the idea of dumb/server-driven clients - which will always produce a slower UX, containing more round trips with a generic un-optimized interface for the task at hand.
This basically fails Comp-Sci 101 where the more generic and abstract you make something the more complex it becomes and the less useful it is.

In my opinion it's a complete pipe-dream that you can have truly autonomous systems where you can roll in new behavior and existing clients can automatically take advantage of it.
It's an un-fulfilled idealistic dream that you can just simply add a new system module (i.e. Ordering system) and existing clients (without updates) can just take advantage of it without having any out-of-band knowledge of it, I could only see it working if everyone adopts universal schemas for new functionality - but in the real word we know this doesn't happen. I've never seen/heard HATEOS work in true B2B systems (where there is no human on the client side inferring and acting on the new rel types / intents).

The other big problem is that it imposes a 'single view' of your system, i.e. the server view - which effectively forces all clients to work and behave exactly the same way. 
If you adopt it, you become 'locked in' to this restrictive system work flow where you can potentially only access a new feature if you transition to it from the 'previous states' up in the heirachy. 
Also it's much harder to participate in a heterogeneous environment accessing services that doesn't implement the same HATEOS service implementation, i.e. I think you'll find it extremely rare to have a client talking to 2+ independent HATEOS systems that weren't developed by the same team. 

This is in contrast to the SOA mindset where you should strive to expose your new capabilities in as interoperable / accessible way possible so it becomes trivially accessible for any client to consume which they can do in any way they see fit.

The best HATEOS-like system and client you'll likely ever to see is your standard client browser navigating HTTP/HTML websites - where we have optimized web frameworks and development tools for building. 
It's infinitely more usable, accessible and stands the best chance of working on all platforms with zero effort of develop HATEOS clients for every platform you wish to support.

Nope not for me, in the end I believe HATEOS was conceived at a time before you can update your clients with an F5. No self-respecting company wanting to provide amazing end-user experiences - it just exists so Cargo cults can waste time Hi 5'ing each other for their attempts at flexing REST theory and getting there CONNEG solution to work. This is the same joy WCF devs get when they've discovered the perfect combination of WCF configuration to get there single service to work in XML, JSON and SOAP at the same time! - meanwhile ServiceStack has been shipping this and more in the default install for years at much better performance.

Personally lifes too short to waste time on fighting frameworks / configuring infrastructure and implementing idealistic impractical system theory that produces sub-par experiences.

In order to shield myself from wasting valuable brain cell space learning dead tech/philosophies like this - I look to to companies I respect that heavily research into what ultimate solution delivers the best end-user experience - So if Google, Apple, Amazon, etc aren't using it (which your services stand no chance in matching in breadth or size) then there's a good possibility that you shouldn't either.

Having said this there are a few good ideas in HATEOS, namely to make your services/API more discoverable, although this doesn't need any kind of 'special or explicit' support to achieve, it simply just involves dumping a list of relevant urls/states (see: BS. REST term from elitist handbook) at the end of your Response DTO. Although I only expect this to be useful for improving the service/API documentation for developers consuming your service at development time, which although is still important, is much less in scope of what HATEOS envisages.

I apologize for the morbid tone of this post but I dislike seeing inefficiencies propagated by devs blindly following advice on developer philosophers (who don't ship real-world systems) without understanding the true benefits of their tech choices so they can assess it for themselves in their own context on its own merits as to whether or not it actually promotes a more productive / maintainable system producing a superior UX - my belief is that in most use-cases it wont - and that the primary motivation for imposing their clients to this tech debt is so they can stay stay subscribed to their REST/HATEOS Cargo Cult  - that needless to say I have personally have no wish to be apart of.

Regards,

Ethan Brown

unread,
Dec 16, 2011, 4:44:47 PM12/16/11
to servic...@googlegroups.com
I struck a nerve!

I wasn't promoting HATEOAS, just giving Greg options since he seemed uncomfortable with URI contracts.  

You should know by now I'm on board with the SS philosophy and a huge fan! ;0


To take this in another direction -- seen the eBay orchestration framework ql.io?

At first take it seems rather awkward / a bandaid for systems with poorly designed APIs, but I haven't had the time to really dig in.  It definitely feels... weird.


-e

Demis Bellot

unread,
Dec 16, 2011, 5:25:19 PM12/16/11
to servic...@googlegroups.com
Hey Ethan,

My response is not directed at anyone here - I just have a dim view of influential devs chasing and preaching over-architecture nirvana but never delivering a compelling end user result.
The amount of waste and tech debt that blindly following the 'party line' creates is disheartening and unfortunately I've seen a lot of millions and many man years wasted in overarchitected systems that never ship because they blindly follow 'so-called consultant' advice promising technical nirvana.

Anyway I purposely went a little overboard so my views were engraved on this thread and it would last through the ages :) Oh and I can link to it when others ask for my views on it :).

Yep I've looked at ql.io it reminds me a lot of oData / IQueryable - Great for adhoc reporting but because it implies a specific implementation it has a way of locking down your system from further changes in a similar way that exposing your internal connection to other systems string would do (i.e. you'd have to make sure that none of your changes to your db schema would break the existing apps accessing your db). If instead all API access happened via the service layer you have complete freedom to make any change to your internal datastores as you know what the external API your clients have binded to.

A great REST idea is to have (impl-agnostic) canonical urls for your resources as it stands the best chance to not break any links even after a complete rewrite of your service, because any new impls would just need to naturally implement the canonical urls.

Cheers,

Reply all
Reply to author
Forward
0 new messages