UrlUtilities
adds functions to construct a URL, HTTP Entity or URL Request in a combine like fashion, by including both Path and Query Parameters, and ensuring their values are properly encoded.
If you find UrlUtilities
useful and would like to help support its continued development and maintenance, please consider making a small donation, especially if you are using it in a commercial product:
It's through the support of contributors like yourself, I can continue to build, release and maintain high-quality, well documented Swift Packages like UrlUtilities
for free.
Swift Package Manager (Xcode 11 and above)
- In Xcode, select the File > Add Package Dependency… menu item.
- Paste
https://github.com/Appracatappra/UrlUtilities.git
in the dialog box. - Follow the Xcode's instruction to complete the installation.
Why not CocoaPods, or Carthage, or etc?
Supporting multiple dependency managers makes maintaining a library exponentially more complicated and time consuming.
Since, the Swift Package Manager is integrated with Xcode 11 (and greater), it's the easiest choice to support going further.
UrlUtilities
includes several functions that are useful when working with RESTful API Endpoints. It includes the following utilities:
URLBuilder
- Assembles a URL String from a base path and any number of path or query parameters.HTTPBodyBuilder
- Assembles the body of aURLRequest
by setting a JSON pattern and filling it with any number of parameters.
Additionally, UrlUtilities
has the following extensions:
String
- Adds theurlEncoded
property which returns the string value properly encoded to send to a URL with any special characters encoded.URLRequest
- Includes the following extensions:defaultAuthorization
- Holds a default authorization string that will automatically be added to anyURLRequest.build
function calls.build(url:URL, data:Data?, method:HttpMethodType = .post, timeout:Double = 10)
- Creates aURLRequest
with the common default values.build(url:URL, method:HttpMethodType = .post, timeout:Double = 10)
- Creates aURLRequest
with the common default values.
UrlUtilities
allows you to construct a URL string from a base path, then add path or query parameters in method similar to adding properties to a SwiftUI View. Take a look at the following example:
let endpoint = URLBuilder("https://api.restendpoint.com")
.addPathParameter(3)
.addPathParameter("login")
.addParameter(name: "username", value: "jdoe")
.addParameter(name: "password", value: "pass123")
// Get the string value
// "https://api.restendpoint.com/3/login?username=jdoe&password=pass123"
let validation = endpoint.urlString
// Ensure we have a good url
guard let url = endpoint.url else {return nil}
In the example above:
addPathParameter
- Appends the given value to the base path directly.addParameter
- Adds a query parameter to the URL in the formname=value
. It will automatically append "?" for the first parameter or "&" for subsequent parameters.
The value can be: String
, Bool
, Int
, Double
, Float
, Color
or Enum
. For Enum
, it must conform to either String, Hashable
or Int Hashable
(see below for details).
Color
will be converted into a hex value in the form #rrggbbaa
using the standard HTTP and CSS syntax.
NOTE: Any string value will be automatically URL Encoded to ensure any special characters don't interfere with the generated URL.
UrlUtilities
makes it east to work with optional parameters. For example:
let sessionID:Int = 0
let username = "YOUR_USSERNAME"
let password = "YOUR_PASSWORD"
let endpoint = URLBuilder("https://login")
.addParameter(name: "username", value: "jdoe")
.addParameter(name: "password", value: "pass123")
.addParameter(name: "sessionID", value: sessionID, onCondition: (sessionID != 0))
In the above example, onCondition
must evaluate to true
before the parameter sessionID
is included. Path parameters work in the same fashion:
let sessionID:Int = 0
let username = "YOUR_USSERNAME"
let password = "YOUR_PASSWORD"
let endpoint = URLBuilder("https://login")
.addPathParameter(sessionID, onCondition: (sessionID != 0))
.addParameter(name: "username", value: "jdoe")
.addParameter(name: "password", value: "pass123")
NOTE: Any
String
parameter that evaluates to the Empty String (""
) will automatically be excluded. The same goes for parameters that evaluate tonil
. You do not need to specifyonCondition
for these types of values.
An Enum
that has a rawValue
of either String
or Int
and also conforms to Hashable
can be used without explicitly specifying rawValue
when adding a parameter. See:
enum UserAccoutType: String, Hashable {
case guest = "guest"
case registered = "registered"
}
let sessionID:Int = 0
let username = "YOUR_USERNAME"
let password = "YOUR_PASSWORD"
let endpoint = URLBuilder("https://login")
.addParameter(name: "username", value: username)
.addParameter(name: "password", value: password)
.addParameter(name: "type", value: UserAccountType.guest)
UrlUtilities
include methods for constructing a URLRequest
body using similar parameter builders. Take the following example:
let apiKey: String = "YOUR_API_KEY"
let sessionID:Int = 0
let username = "YOUR_USERNAME"
let password = "YOUR_PASSWORD"
// Assemble post body.
let body = HTTPBodyBuilder("""
{
"user": "<user>",
"password": "<password>",
"type": "<type>"
}
""")
.addParameter(name: "user", value: username)
.addParameter(name: "password", value: password)
.addParameter(name: "type", value: UserAccoutType.guest)
// Get the string contents
let endpoint = body.dataString
// Get the body data
let data = body.data
Both URLBuilder
and HTTPBodyBuilder
allow you to define a set of Default Parameters that will be included in every URLBuilder
and HTTPBodyBuilder
created. This is useful for items like API Keys that must be sent to every RESTful API Endpoint call.
For example:
let apiKey: String = "YOUR_API_KEY"
let sessionID:Int = 0
// Set API Key
URLBuilder.addDefaultParameter(name: "api_key", value: apiKey)
let endpoint = URLBuilder("https://login")
.addParameter(name: "username", value: "jdoe")
.addParameter(name: "password", value: "pass123")
.addParameter(name: "sessionID", value: sessionID, onCondition: (sessionID != 0))
.urlString
// Get the string value
// "https://login?api_key=YOUR_API_KEY&username=jdoe&password=pass123"
let validation = endpoint.urlString
addDefaultParameter
works exactly like addParameter
and excepts the same data types.
NOTE: If you define a Default Parameter, you can override it later with a
addParameter
call with the same Parameter Name. This will only affect the currentURLBuilder
orHTTPBodyBuilder
instance.To affect all subsequent instances, call
addDefaultParameter
call with the same Parameter Name.
Both URLBuilder
and HTTPBodyBuilder
allow you to find and delete both Parameters and Default Parameters. For example:
let apiKey: String = "YOUR_API_KEY"
let sessionID:Int = 0
// Set API Key
URLBuilder.addDefaultParameter(name: "api_key", value: apiKey)
let endpoint = URLBuilder("https://login")
.addParameter(name: "username", value: "jdoe")
.addParameter(name: "password", value: "pass123")
.addParameter(name: "sessionID", value: sessionID, onCondition: (sessionID != 0))
// Find user name
let name = endpoint.findParameter("username")
// Remove the default API Key
endpoint.deleteParameter("api_key")
UrlUtilities
extends the URLRequest
class with convenience constructors that handle typical requests. Take the following example:
let apiKey: String = "YOUR_API_KEY"
let sessionID:Int = 0
// Set api key
URLBuilder.addDefaultParameter(name: "api_key", value: apiKey)
let endpoint = URLBuilder("https://create-user")
.addParameter(name: "user", value: username)
.addParameter(name: "password", value: password)
.addParameter(name: "sessionID", value: sessionID, onCondition: (sessionID != 0))
guard let url = endpoint.url else {
// Failed to create URLRequest"
return
}
// Assemble post body.
let body = HTTPBodyBuilder("""
{
"user": <user>,
"password": "<password>",
"type": "<type>"
}
""")
.addParameter(name: "username", value: "jdoe")
.addParameter(name: "password", value: "pass123")
.addParameter(name: "type", value: UserAccoutType.registered)
let request = URLRequest.build(url: url, data: body.data)
There is an additional version of URLRequest.build
that doesn't require a body:
let apiKey: String = "YOUR_API_KEY"
let sessionID:Int = 0
// Set api key
URLBuilder.addDefaultParameter(name: "api_key", value: apiKey)
let endpoint = URLBuilder("https://delete-user")
.addParameter(name: "user", value: username)
.addParameter(name: "sessionID", value: sessionID, onCondition: (sessionID != 0))
guard let url = endpoint.url else {
// Failed to create URLRequest"
return
}
let request = URLRequest.build(url: url, method: .delete)
When assembling a URLRequest
with build
if you set the URLRequest.defaultAuthorization
to a string value first, it will automatically be added to the allHTTPHeaderFields
under the Authorization
key.
For example, if you are using a Bearer Token to authorize your requests, you could do the following:
let bearerToken: String = "YOUR_BEARER_TOKEN"
let sessionID:Int = 0
// Set the Bearer Token
URLRequest.defaultAuthorization = "Bearer \(bearerToken)"
let endpoint = URLBuilder("https://delete-user")
.addParameter(name: "user", value: username)
.addParameter(name: "sessionID", value: sessionID, onCondition: (sessionID != 0))
guard let url = endpoint.url else {
// Failed to create URLRequest"
return
}
let request = URLRequest.build(url: url, method: .delete)
The Package includes full DocC Documentation for all of its features.