New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation Question: Requests as Class Methods #324

Closed
andrewjburnett opened this Issue Mar 27, 2015 · 5 comments

Comments

Projects
None yet
2 participants
@andrewjburnett

I'm in the early stages of developing an iOS application, which will consume a REST API. While GitHub, Apple docs, tutorials, etc. have been helpful in answering the majority of my questions thus far, I've recently experienced some hiccups while trying to learn more about networking. I haven't found an good, consolidated source of information regarding best practices/design patterns related to building out the networking layer of an application. I recently came across the source code for Artsy and have been reading over it as a guide to building a framework for consuming an API.

I do have a few questions though. Please, forgive me if they sound naive. Why is that the majority of the actual requests are implemented as class methods? What are the advantages of this approach, as opposed to creating some sort of "shared" singleton, which you would use to instantiate/get an instance of ARRouter and then make requests?

Also, there are calls to these ArstyApi class methods spread throughout. However, I don't understand exactly where/how this class is declared globally, allowing it to be recognized across many different class implementations.

Lastly, do you have plans to "Reactify" any portion of the networking layer. From what I've gathered, ReactiveCocoa and the functional programming it enables is a great fit for code that is heavy with callbacks/handlers, etc. A few other articles and iOS source code examples I have come across (SoundCloud and Timehop) have mentioned that if they haven't already done so, they were at least planning to adopt a more "Reactive" style within upcoming iterations of their code, specifically the networking layer.

Thanks for the help!

@orta

This comment has been minimized.

Show comment
Hide comment
@orta

orta Mar 27, 2015

Member

-writting up now-

Member

orta commented Mar 27, 2015

-writting up now-

@andrewjburnett

This comment has been minimized.

Show comment
Hide comment
@andrewjburnett

andrewjburnett Mar 27, 2015

Accidentally closed this issue. Reopening it now.

Accidentally closed this issue. Reopening it now.

@orta

This comment has been minimized.

Show comment
Hide comment
@orta

orta Mar 27, 2015

Member

Why is that the majority of the actual requests are implemented as class methods?

This is personal, but I've always favoured the look of class methods over [[bleh sharedBlah] method:x y:z] especially for things that feel atomic and stateless. This has changed a little bit over time as I've moved to writing [bleh.sharedBlah method:x y:z] but in general I've not really seen a really strong desire to move in that direction.

Also, there are calls to these ArstyApi class methods spread throughout

Networking is done in 4 ways at the minute,

  • Network Models
  • Promises
  • Model networking
  • Raw API access

They all have different use cases, and came about from different constraints. The network models make it really easy to test code, promise based networking makes it easy to hook a lot of callbacks into the same request, model networking can make it feel like it's just an asychronous call to fetch some data. And accessing the raw api methods is for when we've had time constraints.

There's discussion on our Mobile repo around trying to unify into a single pattern. More on that in your next question.

Lastly, do you have plans to "Reactify" any portion of the networking layer

We've done this once, and it worked out really well. This is the networking stack for Eidolon called Moya, and it looks like this:

  let endpoint: ArtsyAPI = ArtsyAPI.FindBidderRegistration(auctionID: nav.auctionID!, phone: String(self!.number))
  return XAppRequest(endpoint, provider:self!.provider, parameters:endpoint.defaultParameters).filterStatusCode(400).doError { (error) -> Void in

  /// error

  } . then {
    /// return next signal

  }

I'm not entirely sure on how well Moya's enum style can scale for something like eigen, given that for the ~30 routes eidolon uses, it's a 360+ lines of code long API client, even roughly guessing I'd expect eigen to have a hundred plus routes. With a lot more custom messing around. Plus it's swift only, and that's not really production ready for us.

I've explored methods of generating NSURLRequests automatically using documentation so that we can try and concentrate on something that fits similar constraints to what we have for Moya:

  • Can easily run asynchronously or synchronously in tests, and stubs as first class citizens
  • Allow iterating through all potential API requests at runtime for API sanity checks.
  • Enforce using of the API, and not allowing people to take shortcuts
  • A structure that makes it easy to allow multiple listeners to the same request

I've spent time with ReactiveCocoa now, but I'm not sure I'd want to build more things on it personally. The eigen codebase allows you to work with RAC if you choose, but you can also carry on fine wihtout. I wouldn't want our networking to be purely rac based. I think we could re-thing the promise-based networking into a useful system, which is what we were doing a lot in Eidolon.

Member

orta commented Mar 27, 2015

Why is that the majority of the actual requests are implemented as class methods?

This is personal, but I've always favoured the look of class methods over [[bleh sharedBlah] method:x y:z] especially for things that feel atomic and stateless. This has changed a little bit over time as I've moved to writing [bleh.sharedBlah method:x y:z] but in general I've not really seen a really strong desire to move in that direction.

Also, there are calls to these ArstyApi class methods spread throughout

Networking is done in 4 ways at the minute,

  • Network Models
  • Promises
  • Model networking
  • Raw API access

They all have different use cases, and came about from different constraints. The network models make it really easy to test code, promise based networking makes it easy to hook a lot of callbacks into the same request, model networking can make it feel like it's just an asychronous call to fetch some data. And accessing the raw api methods is for when we've had time constraints.

There's discussion on our Mobile repo around trying to unify into a single pattern. More on that in your next question.

Lastly, do you have plans to "Reactify" any portion of the networking layer

We've done this once, and it worked out really well. This is the networking stack for Eidolon called Moya, and it looks like this:

  let endpoint: ArtsyAPI = ArtsyAPI.FindBidderRegistration(auctionID: nav.auctionID!, phone: String(self!.number))
  return XAppRequest(endpoint, provider:self!.provider, parameters:endpoint.defaultParameters).filterStatusCode(400).doError { (error) -> Void in

  /// error

  } . then {
    /// return next signal

  }

I'm not entirely sure on how well Moya's enum style can scale for something like eigen, given that for the ~30 routes eidolon uses, it's a 360+ lines of code long API client, even roughly guessing I'd expect eigen to have a hundred plus routes. With a lot more custom messing around. Plus it's swift only, and that's not really production ready for us.

I've explored methods of generating NSURLRequests automatically using documentation so that we can try and concentrate on something that fits similar constraints to what we have for Moya:

  • Can easily run asynchronously or synchronously in tests, and stubs as first class citizens
  • Allow iterating through all potential API requests at runtime for API sanity checks.
  • Enforce using of the API, and not allowing people to take shortcuts
  • A structure that makes it easy to allow multiple listeners to the same request

I've spent time with ReactiveCocoa now, but I'm not sure I'd want to build more things on it personally. The eigen codebase allows you to work with RAC if you choose, but you can also carry on fine wihtout. I wouldn't want our networking to be purely rac based. I think we could re-thing the promise-based networking into a useful system, which is what we were doing a lot in Eidolon.

@andrewjburnett

This comment has been minimized.

Show comment
Hide comment
@andrewjburnett

andrewjburnett Mar 27, 2015

Thank you very much! Going to read this over and soak it in.

Thank you very much! Going to read this over and soak it in.

@orta orta added the Question label Apr 9, 2015

@orta

This comment has been minimized.

Show comment
Hide comment
@orta

orta Apr 9, 2015

Member

Closing for now, would recommend keeping an eye on artsy/mobile#22 for upcoming ideas around this

Member

orta commented Apr 9, 2015

Closing for now, would recommend keeping an eye on artsy/mobile#22 for upcoming ideas around this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment