Neorequest 1.0.0

Neorequest 1.0.0

TestsTested
LangLanguage SwiftSwift
License Apache 2
ReleasedLast Release Aug 2017
SwiftSwift Version 3.1
SPMSupports SPM

Maintained by Edison Santiago.


Downloads

Total12
Week1
Month7

Installs

Apps2
Apps WeekApps This Week 1
powered by Segment

 
Depends on:
SwiftHTTP~> 2.0.0
Locksmith>= 0
PKHUD~> 4.0
 

  • By
  • Neomode

Neorequest

Neorequest is a simple wrapper around SwiftHTTP with some extras features and providing a cleaner syntax by decoupling error and sucess handling.

Features

  • Cleaner syntax, with separate closures for managing error and success of the request
  • JSON Parsing of the response
  • Request Authorization management
  • Management of loading indicators on the view

Installation

CocoaPods

Neorequest is available through CocoaPods. Just add pod 'Neorequest' to your Podfile and run pod install

Getting Started

Creating a simple request

Making a request with Neorequest is as simple as:

Neorequest.GET(
	url: "https://yoururl.com",
	onError: {
		error in
		//Handle request error here
	},
	onSuccess: {
		jsonObj in
		//Handle success response here
	}
)

Sending parameters

You can simply pass a Dictionary<String: Any> to the parameters property with the data you want to send.

Neorequest.POST(
	url: "https://yoururl.com",
	parameters: ["name": "John Doe", "age": 7],
	onError: {
		error in
		//Handle request error here
	},
	onSuccess: {
		jsonObj in
		//Handle success response here
	}
)

For uploading files you can refer to the Swift HTTP Upload and simply pass the Upload object as a parameter. To learn how to send a form-data request please refer to the NeorequestConfiguration section of this file.

Reading the response

onSuccess((JSONObject) -> Void)) receives an object of theJSONObject type (which is just a typealias for Dictionary<String, Any> to make the code more readable).

You can retrieve the values for the response values the same way you do with any Dictionary:

Neorequest.GET(
	url: "https://yoururl.com",
	onError: {
		error in
		//Handle request error here
	},
	onSuccess: {
		jsonObj in
		if let name = jsonObj["name"] as? String {
			//do something with the name here
		}
	}
)

Please note that the response is always parsed to JSON. If the response is empty you get an empty JSONObject. If the data can't be parsed to JSON the onError closure will be called with an error NeorequestError.ParseError(content: String?), where content is a conversion of the original Data received to String.

JSON Arrays on first level are supported by Neorequest. Since the response object is always an JSONObject if your remote API returns a first level array you can easily access it using the key Neorequest.JSONObjectArrayKey, which will return a JSONArray object (a typealias for an array of JSONObject).

Neorequest.GET(
	url: "https://yoururl.com",
	onError: {
		error in
		//Handle request error here
	},
	onSuccess: {
		jsonObj in
		if let persons = jsonObj[Neorequest.JSONObjectArrayKey] as? JSONArray {
			for person in persons {
				//Do something with the persons here
			}
		}
	}
)

Global Headers

If you must include a custom HTTP header in all the requests made on your app you can simply add it to Neorequest.globalHeaders: [String:String].

import Neorequest

Neorequest.globalHeaders.append(["headerName":"headerValue"])

Do not set the Authorization HTTP header here if you are using NeorequestAuthorization.

NeorequestConfiguration

The NeorequestConfiguration struct let you set some specific configurations of the request. We put this parameters on a separate struct so the main request call doesn't get bloated with parameters that won't be used all the time.

Please note that all requests has an associated NeorequestConfiguration with it. If no configuration object is passed one with the default values specified below is created.

NeorequestConfiguration Properties

  • loadingType: A enum telling if we sould show a loading on the desired view along the request. You can show a fullScreen loading or an overScreen loading, as specified below. The default value is none and no loading is shown unless specified.
    • fullScreen(loadingViewController: UIViewController, loadingIconColor: UIColor?): A overlay view is created on top of all UIViewController views with the same backgroundColor as the viewController.view object with an UIActivityIndicator centered and with the desired color.
    • overScreen: We rely on PKHUD to show a loading over the entire app when this mode is set. Since PKHUD uses UIWindow there's no need to a reference of the UIViewController to display the loading onto.
  • numberOfRetries: Int: How many times the request should fail before calling the error handler. Default: 1
  • isJsonRequest: Bool: Specify if the request must not be sent as json. If set to false we sent the request as x-www-form-urlencoded (but the response is always treated as json). Default: true
  • progress: ((Float) -> Void)?: The progress closure to be set on the original Request. For more information on this please refer to the SwiftHTTP Documentation. Default: nil
  • onOperationCreated: ((HTTP) -> Void)?: A closure called with the original Operation object after it's creation if you want to use NSOperationQueue. Default: nil

NeorequestConfiguration Examples

  • Show a gray loading over the entire view while a request is made:
import Neorequest

var config = NeorequestConfiguration()
config.loadingType = .fullScreen(
   loadingViewController: myViewController,
   loadingIconColor: UIColor.lightGray
)

Neorequest.GET(
	url: "https://yoururl.com",
	configuration: config,
	onError: {
		error in
		//Handle request error here
	},
	onSuccess: {
		jsonObj in
		//Handle success response here
	}
)
  • Send a form-data request, retry 10 times and show a overScreen loading while a request is made:
import Neorequest

var config = NeorequestConfiguration()
config.isJsonRequest = false
config.numberOfRetries = 10
config.loadingType = .overScreen

Neorequest.GET(
	url: "https://yoururl.com",
	configuration: config,
	onError: {
		error in
		//Handle request error here
	},
	onSuccess: {
		jsonObj in
		//Handle success response here
	}
)

NeorequestAuthorization

NeorequestAuthorization is a singleton class that provides a simple way to manage the authorization of all the requests across the entire app. It handles the token expiration and regeneration for you, so you don't need to worry if the token is still valid or not before making a request. If needded, they will be regenerated before the request proceeds. The NeorequestAuthorization data is used by default on all HTTP requests made after the values are saved. If you need to make a call where the authorization must not be used (i.e., the authentication request) you can specify it with authorization: nil on the request call.

Neorequest.POST(
	url: "https://yoururl.com",
	authorization: nil,
	parameters: ["name": "John Doe", "age": 7],
	onError: {
		error in
		//Handle request error here
	},
	onSuccess: {
		jsonObj in
		//Handle success response here
	}
)

Properties

NeorequestAuthorization has some properties to hold the values used on the authorization. All the data is saved only on the iOS Keychain, using Locksmith, so the user sensitive information can be kept secure.

  • authType: We support bearer authorization, basic auth and also a custom authorization method where you must provide the tokenString generation. Default: NeorequestAuthorizationType.bearer
  • account: String?, password: String?: Save the authentication info only once so you can retrieve it later during the token generation process. Default: nil
  • tokenString: String? | tokenExpirationDate: Date? | tokenUsageTime: TimeInterval: Manage the token regeneration. The token is only regenerated when needed, and in .bearer mode the class manage this by itself and knows when to regenerate the token. The default tokenUsageTime is 1800.

Closures

While NeorequestAuthorization manages a lot of stuff automatically, you need to set some closures with some specific logic for you app if you are using .bearer or .custom auth.

Bearer authentication

  • NeorequestAuthorization.regenerateBearerTokenHandler((NeorequestAuthorization, onError: ((NeorequestError) -> Void), onSuccess: (() -> Void)) -> Void)
    • This closure is responsible for (re)generating the token when needed and checking if it is successfull or not. If the user data was already set previously the NeorequestAuthorization object passed to it contains all the info you previously saved, so you can retrieve then now. Please remember that this method can be called during other requests, so always calls onError and onSucess to make sure that the other request can continue.
    • Since the token is always regenerated when the remote API returns an 401 Not Authorized, you can get in a loop if you try to make a request with bad authentication data. Because of this, the user data will not be saved automatically, and you should call .save() when you are sure check the credentials are valid. After the user data are saved and a token is generated you no longer need to worry about it and all will be handled for you.
    • This closure must be set before you make any request in bearer mode, so we recommend setting it on the app initialization.

Custom authentication

  • NeorequestAuthorization.regenerateCustomTokenHandler((NeorequestAuthorization, @escaping ((NeorequestError) -> Void), @escaping (() -> Void)) -> Void)

    • Has the same functionality as regenerateBearerTokenHandler. Please refer to this closure explanation above for more info.
  • NeorequestAuthorization.getCustomValidAuthHeaderStringHandler((NeorequestAuthorization, @escaping ((NeorequestError) -> Void), @escaping ((String) -> Void)) -> Void)

    • Use this method to provide a valid string to be used on the Authorization header of the string. Since you are using a custom auth we can't do this for you.
    • In this handler you should verify if we must renew the token using the parameters of NeorequestAuthorization or if the saved token is still valid. If needed, you can call .regenerateCustomTokenHandler to get another token.
    • You should pass the value of the Authorization HTTP header to the onSucess closure. If you need to append any fixed value to the header it please do it here.

Saving and removing user data

Saving new data

Create a new instance of the NeorequestAuthorization, set the desired properties and regenerate the token. The regenerateBearerTokenHandler you provided must save the new values. Please note that saving new data will override any existing data since we still do not support handling multiple accounts.

let auth = NeorequestAuthorization()
auth.account = "account"
auth.password = "password"
auth.regenerateBearerToken(
	onError: {
		error in
		//Manage the error
	},
	onSuccess: {
		//User authenticated and token regenerated
	}
)

Retrieving saved data

NeorequestAuthorization.load() will return an object with all the info initialized from the keychain if it exists or return nil if no data is saved on the keychain.

Force token regeneration

If for some reason you must force a token regeneration on the next request you can call expirateToken on a populated object, which will set the token as expired and it will be renewed at the next request. To regenerate the token right now you can use regenerateBearerToken(onError: ((NeorequestError) -> Void), onSuccess: @escaping (() -> Void)).

Remove existing data

NeorequestAuthorization.load()?.delete() will remove any existing data.

###Examples

Set the token regeneration handler on app initiation

import Neorequest

NeorequestAuthorization.regenerateBearerTokenHandler = {
	auth, onError, onSuccess in
	
	//The remote api authentication endpoint uses x-www-form-url-encoded
	var config = NeorequestConfiguration()
    config.isJsonRequest = false 

	Neorequest.POST(
		url: "http://yoururl.com/auth",
		authorization: nil,
		parameters: ["account": auth.account, "password": auth.password],
		configuration: config,
		onError: onError, //Call the error handler passed as parameters so we return to the original request 
		onSuccess: {
			jsonObj in
			//Retrieve the token and save it
			auth.tokenString = "..."
	
			//Since the request is valid we can save the auth date now
			auth.save()
			
			//Proceed with the request
			onSuccess()
		}
	)
}

Log an user in for the first time and save it's data

import Neorequest

let auth = NeorequestAuthorization()
auth.account = account
auth.password = password
auth.regenerateBearerToken(
	onError: {
		error in
		//Problem regenerating the token. Maybe the user provided bad credentials?
	},
    onSuccess: {
		//Token regenerated. Proceed with the next requests
	}
)

##License

Neorequest is licensed under the Apache v2 License. See the LICENSE file for more info.