Search code examples
swiftenumsalamofire

Using Enum features to create a Network Abstraction API


I am following a design I cam across that uses Enum's to essentially construct a network request in a way that exposes en elegant API. Basically, it leverages associated values to progressively construct the information (in the form of computed properties on the Enum) that is sent to an Alamofire function call.

The problem I'm having is that each computed property in the Enum actually requires a different value from the cases' associated values.

So If I declare an endpoint endpoint1(path: String, param1: String) the path property would access just the first value. Unfortunately, given the way Swift Enums work, it seems I must expose all associated values for each case that is switched on. This results in unused variables and therefore must be incorrect. Therefore, I am thinking of scraping this approach.

For reference, this is my code that uses an Enum case to form a conceptual network endpoint. Which could be invoked like Endpoint1(path: users/, format: "JSON").

    public enum Endpoints {

        case Endpoint1(path: Sring, param1Value: String)

        public var method: HttpMethod {
            switch self {

            case .Endpoint1,

                return HttpMethod.GET
            }
        }

        public var path: String {
            switch self {
            case .Endpoint1(let path, let paramValue1):
                return baseURL + path 
            }
        }

        public var parameters: [String : AnyObject] {
            var parameters = ["param1" : "..."]
            switch self {
            case .Endpoint1(let path, let param1Value):
                parameters["param1"] = param1Value
                break
            }
            return parameters
        }

}

So the problem is that the path property doesn't need the paramValue1 associated value and the parameters property doesn't need the path associated value.

Despite being a bit complex, I actually like this technique of using Enum features in this way. Unfortunately, this aspect of their functionality seems to be a dead-end. Is there a way I could refactor this to work with Swift Enums properly?


Solution

  • The definition of EndPoint should be parameter list rather than values. I update your code to Swift 3:

    public enum Endpoints {
    
        case endpoint1(path: String, parameters: [String])
    
        public var method: HttpMethod {
            switch self {
            case .endpoint1:
                return .get
            }
        }
    
        public func path(_ baseURL: String) -> String {
            switch self {
            case .endpoint1(let path, _):
                return baseURL + path
            }
        }
    
        public func parameters(_ values: [Any?]) -> [String: Any] {
            var parameters = [String: Any]()
            switch self {
            case .endpoint1(_, let params):
                for (index, param) in params.enumerated() {
                    if let v = values[index] {
                        parameters[param] = v
                    }
                }
            }
            return parameters
        }
    
    }
    
    let endpoint = Endpoints.endpoint1(path: "/users", parameters: ["sort"])
    let params = endpoint.parameters(["desc"])
    let path = endpoint.path("http://10.1.1.1")
    

    Use function instead of ivar to get path and parameters so you can pass in baseURL and parameters variants. I hope this will help you decide whether you still want to use Enum for it or not.