bustoutsolutions / siesta

The civilized way to write REST API clients for iOS / macOS
https://bustoutsolutions.github.io/siesta/
MIT License
2.19k stars 159 forks source link

Working with highly non-RESTful APIs (was: Ability to set a request method for a Resource) #81

Open cemaleker opened 8 years ago

cemaleker commented 8 years ago

Today I had a chance to try Siesta in a real world example. And I found out that all resource API built assuming a resource would only be loaded with a GET request.

This looks clean and straightforward at first look. But I think building upon this assumption will greatly restrict Siesta's usability in real world application. I am still struggling daily with API's only built on POST request. And it's really not easy to push API developers to conform to universal REST API principles.

BTW I know it is possible to execute a post request with a resource. But with that approach all the magic that Siesta provides flies away. I can not call loadIfNeeded(), I can not attach observes. I can only execute an HTTP request. This means if my API is not fully REST there's no point to use Siesta at all.

Wouldn't it be much more flexible if we can pass request's method and possibly other parameters when creating a Resource. And with a brief analysis of the Resource API I can say it's really easy to implement.

It would be even more usable to be able to configure Resource's request methods with Service configuration but I don't fully understand the Service configuration API yet so please provide some information on this issue if you can.

I love Sieasta's resource-centric approach and effort to decouple UI and network layer. I'll try to implement the idea. Meanwhile please share your thoughts on this humble proposal of mine.

pcantrell commented 8 years ago

Yeah, this is a well-noted limitation of Siesta as it stands — it really does assume your API is RESTful, at least in GET requests having that special status. If you’re using, say, a SOAP API, then you’re out of luck.

Not all the machinery is there for this problem to be solved, but it’s close. The solution will be to apply service-wide configuration that modifies the NSURLRequests for all resources before they go out. You’d then specify resources with virtual URLs like /foo/bar, and they’d get transformed into, say, POST with <stupidEnvelope><resource>foo.bar</resource></stupidEnvelope>.

This machinery for request warping & wrapping is up soon on my dev list, but not there yet.

onekiloparsec commented 8 years ago

That's one of the very motivation for writing middlewares...

pcantrell commented 8 years ago

Mulling this over a little more, I think the right way to handle this is with a custom NetworkProvider implementation that rewrites and then forwards the URLRequest. To Siesta, your API looks restful; it’s only in the network layer that you rewrite GET /widget as POST /nastySoapEndpointOrWhatever. This is more or less the Siesta version of what @onekiloparsec mentioned.

That should be quite robust, and is supported with Siesta’s API today.

I’ll leave this issue open as a reminder to write an example of this — or as a request for someone else to!

xtravar commented 7 years ago

I've been researching making a very similar framework recently and I'm excited to see someone else out there experimenting along the same lines.

Since I'm dealing with only RPCs, my idea is to have client-side identifiers replace URLs completely, offering more concise client code. So, maybe your API doesn't need HTTP/URLs in the first place and you can separate the network layer completely. My 2 cents. YMMV.

pcantrell commented 7 years ago

@xtravar That sounds a lot like the abstraction Moya provides over Alamofire? I considered that, but it seemed like solving too many problems at once.

Even without that, it’s pretty easy with the Siesta API as it stands to make your own URL-free wrapper for a specific service. The GithubBrowser example project does a light version of this: you get resources with calls like GithubAPI.repository(ownedBy: "bustoutsolutions", named: "siesta"), no knowledge of URL structure needed in app code.

xtravar commented 7 years ago

Ashamed to say - I don't know a whole lot about Moya. Quick perusal of Moya's readme seems that it's not cache-observer based, which I think is really (one of) the key components of all of this. I just stopped by to comment that I think you can open up a world of possibilities by not tightly coupling the API to network fundamentals.

Surely, Siesta is revolutionary and suitable for a great number of projects, and my intention isn't to bust in and criticize or demand features. I'm designing for an application with many interdependent, wide-ranging legacy RPC services, so my perspective is slightly different. I've solved my networking abstractions, and I'm focused on solving data-flow issues.

I'd love to take the conversation into email or something to compare notes on inspiration, research, and similar projects. Thus far, Siesta is the closest project I've found to validating the design I've been working on.

pcantrell commented 7 years ago

Quick perusal of Moya's readme seems that it's not cache-observer based

Right, right, sorry — I meant that what you were describing sounded to Siesta as Moya is to Alamofire, not that Moya is what you are looking for.

Perhaps, though, you're thinking of something more general? Building Siesta, I originally considered making it two separate projects: an abstract observable cache with a graph structure, and a REST data provider that would one possible implementation of a data provider protocol. The data provider would allow arbitrary mapping between cache entries and requests, and the cache would have no knowledge of underlying request structure (HTTP or otherwise). This would open all sorts of interesting applications. It would also provide the oft-requested ability to make an index request update cache entries for both the whole collection.

Lovely as that sounds, it’s a much deeper problem, and I decided it was better to bite off a tractable piece that served my concrete needs, and perhaps generalize from that later. One thing I love about Siesta is that it’s small — and even so it still untangles enough tricky problems that I’m glad it doesn’t take on more.

I'd love to compare notes on the grander vision, although my semester starts in a couple of weeks and I'm wrapping up some project work before then, so I probably won’t be a very good correspondent!

AlexisQapa commented 5 years ago

Hi, @pcantrell

I tried to have a resource which aggregate results from multiples network calls. This is not supported by siesta at first but your comment (https://github.com/bustoutsolutions/siesta/issues/81#issuecomment-245502826) made me think that I could implement this into the network provider. Did you publish an example like the one mentioned in your comment.

I think this is a common use case where you download the user profile but you also want some extra data. Having them grouped under the same resource would allow avoiding dancing with the syncing at higher level.

pcantrell commented 5 years ago

Hi Alexis. I don't have an example like that. You might want to investigate whether request decorators and chained requests might help you.