Basics of Swift Enumeration for Constructing Rest Web Service Request

06 / Apr / 2017 by Ankit Nigam 0 comments

Enum

Are you a software engineer? Heard about data types? We are sure you must have heard about various data types and their usage for a very long time now.

In this blog, we will talk about enums and their use in constructing rest web-service request. Firstly, we would understand a few basics of Swift Enum.

What is Swift Enum?

“Enums declare types with finite sets of possible states and accompanying values. With nesting, methods, associated values, and pattern matching, however, enums can define any hierarchically organized data.”

Now, let us also understand and define Basic Enum:

enum Enumname {
// enumeration definition goes here
}

In this blog, we are discussing a use case of leveraging an enum for creating an API request. We are discussing this further below.

enum Apirouter {
case loginRequest
case registrationRequest
case forgotPasswordRequest
}

This API router enum is a basic enum that will hold all the API requests we make in our application and this echoes the enum definition “finite sets of possible states and accompanying values”.

Moving on, let’s assume a function that takes enum API router as a parameter and returning its URL to make service request. Outlined below are the explanations for “pattern matching “.

func getApiUrl(requestRoute : Apirouter) -> URL
{
switch requestRoute {
case .loginRequest:
return URL(string: "http://www.test.com/login")!
case .registrationRequest:
return URL(string: "http://www.test.com/register")!
case .forgotPasswordRequest:
return URL(string:"http://www.test.com/forgotpassword")!
}
}

As it is obvious, we are matching the request type and returning the URL for that request.

What are Enum Values?

Sometimes we may need to assign values to enum case. For an instance, we can assign URL string to each of our cases and get rid of the function we created above. It is, therefore, a mandate to have URL type attached to our enum case, but this is where Swift restricts us. It allows only below-mentioned types:

  • Integer
  • Floating Point
  • String
  • Boolean

If there is a need to support something else, you can do so by implementing the StringLiteralConvertible protocol that allows the type in question to be serialized from the string. We’ll see an advanced usage of enum in other use case topic.

enum Apirouter {
case loginRequest = "http://www.test.com/login"
case registrationRequest = "http://www.test.com/register"
case forgotPasswordRequest = "http://www.test.com/forgotpassword"
}

Usage

let apiRouter = Apirouter.loginRequest
print(apiRouter.rawValue)
// prints http://www.test.com/login

We just saw how an enum could hold up the values as raw. However, there is something more to this –  Associated Values.

What is an Associated Value?

Associated values help to attach additional information to an enum case. Let us take an example of creating an API request with post parameters. Here, our web request accepts username and password as a parameter. Outlined below is how our enum API Router will appear:

enum Apirouter {
// 1
static let baseUrl = "http://www.test.com/"
// 2
case loginRequest(param : Dictionary<String,String>)
case registrationRequest
case forgotPasswordRequest
// 3
var url:String{
get{
switch self{
case .NewsListPostRequest:
return baseUrl + "login"
default:break
}
}
}
// 4
var parameter : Dictionary<String,String>{
get{
var paramsDictionary = Dictionary<String,String>()
switch self {
case .NewsListPostRequest(let dictionary):
paramsDictionary = dictionary
default:break
}
return paramsDictionary
}
}
}

Now you must be able to see some massive change in our enum. Let us explain each tag and walk you through the use of typed properties and computed properties, the content of which is based on the enum raw values or enum associated values.

If you are familiar with swift properties, you might be thinking of how we missed the use of stored property. Well, an enum can’t have stored properties!

Here’s the breakdown of our enum:

  • We have used the typed property which belongs to the type itself and not to any of the instances of that type. There will only be one copy of these properties no matter how many instances of that particular type are created. We assume here that we hardly have multiple base URLs and are not changing them for our request. With this, it makes sense to use typed properties for defining base URL. You define the type properties with the static keyword.
  • It can be read as an enumeration of type API router which can take a value of loginRequest with an associated value of type (Dictionary<String,String>).
  • As mentioned above, we have made use of computed property to create our web service request url string. For simplicity sake, we have created String type but you can always use the URL type.
  • Again, this time we could use computed property. However, this time we are extracting the associated value and our computed property get its value when accessed through any one of the instances.

Finally, let us also understand creating an API router instance and using it further:

let loginDic = [“username": “ankit.nigam@test.com”, "password" : “123456”]
let loginRequestType = Apirouter.loginRequest(param: loginDic)

In the above code, we have created our request type that holds our request URL, request parameters and you can also do much more. You can define the request methods such as POST, GET, PUT, DELETE, and PATCH using computed property for each requests. We love Alamofire Networking library for making an API request and hence we have created a method for our login post request. This is a type method and here we have kept this method in “Service Manager” class and call this method passing it our loginRequestType as a parameter along with your Closure as completion handler.

class func requestPOSTURL(requestType: Apirouter, success:@escaping (Apirouter,JSON) -> Void, failure:@escaping (Error?) -> Void){
Alamofire.request(requestType.url, method: .post, parameters: requestType.parameter, encoding: JSONEncoding.default, headers: requestType.headers).validate().responseJSON { (responseObject) -> Void in
//Need to add Success and Failure handlers
}
}

Hope this blog was helpful and we could provide you information on using ENUM and its practical usage with REST API ENDPOINTS.

FOUND THIS USEFUL? SHARE IT

Leave a comment -