carson-katri / swift-request

Declarative HTTP networking, designed for SwiftUI
MIT License
727 stars 41 forks source link

Discussion: New structure for declarative programming #40

Closed o-nnerb closed 3 years ago

o-nnerb commented 3 years ago

I would like to suggest a better and clean way to create declarative objects.

The idea is to make RequestParam a generic protocol with a static function like that:

protocol RequestParam {
    static func _buildRequest(_ param: Self /* or RequestParam */) -> URLRequest
    // or
    static func _buildRequest(_ param: Self, _ request: URLRequest) -> URLRequest /* or Void */
}

struct Body: RequestParam {
    private let data: Data?
    /// Creates the `Body` from key-value pairs
    public init(_ dict: [String:Any]) {
        self.value = try? JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
    }

    /// Creates the `Body` from an `Encodable` type using `JSONEncoder`
    public init<T: Encodable>(_ value: T) {
        self.value = try? JSONEncoder().encode(value)
    }

    /// Creates the `Body` from a `String`
    public init(_ string: String) {
        self.value = string.data(using: .utf8)
    }

    public static func _buildRequest(_ param: Self, _ request: URLRequest) -> URLRequest {
        var request = request
        request.httpBody = param.data
        return request
    }
}
o-nnerb commented 3 years ago

You can work with opaque type but I don't know very much about that technique

carson-katri commented 3 years ago

Great suggestion. I think we'll have to avoid Self in the protocol so we can form an Array of the items. It would probably work well without being a static func:

protocol RequestParam {
  /// Here the param can modify the `URLRequest` in any way necessary.
  func buildParam(_ request: inout URLRequest)
}
struct Body: RequestParam {
  ...
  public func buildParam(_ request: inout URLRequest) {
    request.httpBody = data
  }
}

We may also want to pass the URLSession in case they need to modify that. This also opens the possibility for user-created params :)

o-nnerb commented 3 years ago

Awesome suggestion! This will make request so much cleaner 👏🏻

o-nnerb commented 3 years ago

I will keep this topic open so we can track PR and discuss at any time.

About URLSession, I guess that this could be pass to RequestParam or maybe to other protocol that extends RequestParam, so Request struct can call the function, for example, trackSession(_ session: URLSession), after request starts.