vadymmarkov / Malibu

:surfer: Malibu is a networking library built on promises
https://vadymmarkov.github.io
Other
414 stars 39 forks source link

Feature: endpoints #59

Closed vadymmarkov closed 7 years ago

vadymmarkov commented 7 years ago

This is a super breaking change, so the next version should be Malibu 3.

We used structs to describe requests for a while and it worked, but it wasn't the most elegant solution. I see libraries like https://github.com/Moya/Moya and https://github.com/kickstarter/ios-ksapi/blob/master/KsApi/lib/Route.swift use enum for this and I think it looks really nice. Based on this idea I've made the following API changes:

1. Endpoint

Additional headers, base url and request description are moved to Endpoint. There are no Requestable protocols anymore, they are replaced by Request struct with helper get, post, patch, put, delete and head methods:

enum SharkywatersService: Endpoint {
  // Describe requests
  case fetchBoards
  case showBoard(id: Int)
  case createBoard(type: Int, title: String)
  case updateBoard(id: Int, type: Int, title: String)
  case deleteBoard(id: Int)

  // Every request will be scoped by the base url
  static var baseUrl: URLStringConvertible = "http://sharkywaters.com/api/"

  // Additional headers for every request
  static var headers: [String: String] = [
    "Accept" : "application/json"
  ]

  // Build requests
  var request: Request {
    switch self {
    case .fetchBoards:
      return Request.get("boards")
    case .showBoard(let id):
      // Let's use JSON dictionary as a mock data
      return Request.get("boards:\(id)", mock: Mock(json: ["type": 1, "title": "Classic"]))
    case .createBoard(let type, let title):
      return Request.post("boards", parameters: ["type": type, "title": title])
    case .updateBoard(let id, let title):
      return Request.patch("boards\(id)", parameters: ["title": title])
    case .deleteBoard(let id):
      return Request.delete("boards\(id)")
    }
  }
}

let networking = Networking<SharkywatersService>()
networking.request(.fetchBoards)

2. Networking is endpoint-specific:

let networking = Networking<SharkywatersService>(
  // `OperationQueue` Mode
  mode: .async,
  // Mock behavior (never, delayed)
  mockBehavior: .delayed(0.5),
  // `default`, `ephemeral`, `background` or `custom`
  sessionConfiguration: .default,
  // Custom `URLSessionDelegate` could set if needed
  sessionDelegate: self
)

3. There is no networking container anymore, it's up to developer to create and keep Networking instances.

4. Mocks are created directly on a request:

let request = Request.get(
  "boards",
  mock: Mock(fileName: "boards.json")
)

I think it simplifies the way requests are described and used, plus it's gonna remove a lot of boilerplate code from our projects.

onmyway133 commented 7 years ago

Looks great 🚀

onmyway133 commented 7 years ago

@vadymmarkov Look like travis is yelling "TEST FAIL"

vadymmarkov commented 7 years ago

@onmyway133 I can't understand what is wrong there. Tests are passing on my machine 😬

onmyway133 commented 7 years ago

💥

viktorgardart commented 7 years ago

🎉 🍾

zenangst commented 7 years ago

This looks awesome!