TestsTested | ✗ |
LangLanguage | SwiftSwift |
License | MIT |
ReleasedLast Release | Jan 2018 |
SwiftSwift Version | 3.0 |
SPMSupports SPM | ✓ |
Maintained by doozMen, Jelle Vandebeeck, Leroy Jenkins.
======
For a quick start follow the instructions below. For more in depth information on why and how we build Faro, visit the wiki page.
Version 2.0 is compatible with 1.0 but you will have to read the changelog and follow the migration hints.
We build a service request by using a Service
class as the point where you fire your Call
and get a ResultFunction. The function is composed of the code that will be executed after the Server has responded. Use this function to evaluate the response and get the requested model or a thrown error.
Error handling
FaroError
Service
Call
.Automagically Parse
Protocols
NSManagedObject
💪🏼Mocking
FaroSingleton
singleton if you want to switch between data from the server or a file.Security
FaroSecureURLSession
is created for this purpose.
You can write your example service so that a call becomes a oneliner.
let call = Call(path: "posts", method: HTTPMethod.GET, rootNode: "rootNode")
// the rootNode is used to query the json in the response in `rootNode(from json:)`
TIP: Take a look at the
ServiceSpec
,
In short the repsonse can be:
JSONDeserializable
type.and this for any HTTPMethod but lets presume we have:
let call = Call(path: "posts")
let config = Configuration(baseURL: "http://jsonplaceholder.typicode.com"
let service = Service<Post>(call, deprecatedService: DeprecatedService(configuration: config)
This reads like we would like to make a call
to baseURL in config
that will be deserialized into a type Post
.
Optionally setup a Service Singleton. For example in the appdelegate after startup.
let baseURL = "http://jsonplaceholder.typicode.com"
// Optionally create your own FaroSession to handle for example security.
FaroSingleton.setup(with: baseURL, session: FaroSession())
Long version
service.collection { [weak self] (resultFunction) in
DispatchQueue.main.async {
do {
let posts = try resultFunction() // Use the function to get the result or the error thrown
self?.label.text = "Performed call for \(posts)"
} catch {
// printError(error) // errors are printed by default so you could leave this out
}
}
}
Short version
service.collection {
DispatchQueue.main.async {
let posts = try? $0() // Us anonymous closure arguments if you are comfortable with the syntax
self?.label.text = "Performed call for posts"
}
}
Short version
service.single {
DispatchQueue.main.async {
do {
let model = try $0()
print("🙏 sucessfully finished call")
} catch {
print("👿 something went wrong with \(error)")
}
}
}
This is typically for a HTTPMethod POST
. Short version
service.sendWithoutJSONInResponse {
DispatchQueue.main.async {
do {
try $0()
print("🙏 sucessfully finished call")
} catch {
print("👿 something went wrong with \(error)")
}
}
}
Because we throw errors and print them by default you should always know where things go wrong. When an error occurs two things will happen:
Service
there is a function handleError
that will get called on any error. By default this function prints the error. You can override this if neededFaroError
.For example if you want to retry a request when you receive Unauthorized
(401) you can.
// Do any Service call like above
do {
let _ = try resultFunction()
} cacht FaroError.invalidAuthentication(call: let call):
// Handle this specific error case
catch {
// Handle all other possible errors.
print("👿 something went wrong with \(error)")
}
Deserialization and Serialization can happen automagically. For a more detailed example you can take a look at the ParseableSpec tests.
You can parse:
class Zoo: JSONDeserializable {
var uuid: String?
var color: String?
var animal: Animal?
var date: Date?
var animalArray: [Animal]?
required init(_ raw: [String: Any]) throws {
self.uuid |< raw["uuid"]
self.color |< raw["color"]
self.animal |< raw["animal"]
self.animalArray |< raw["animalArray"]
self.date |< (raw["date"], "yyyy-MM-dd")
}
}
extension Zoo: JSONSerializable {
var json: [String: Any] {
get {
var json = [String: Any]()
json["uuid"] <| self.uuid
json["color"] <| self.color
json["animal"] <| self.animal
json["animalArray"] <| self.animalArray
json["date"] <| self.date
return json
}
}
}
Because swift requires all properties to be set before we can call map(from:)
on self
you will have to do required properties manually.
class Jail: JSONDeserializable {
var cellNumber: String
required init(_ raw: [String: Any]) throws {
cellNumber = try create("cellNumber", from: raw)
}
}
The model should implement JSONUpdateable
and you use ServiceUpdate<T>
.
You can use Faro
to send a multipart/form-data
to a server. To use this, you add the multipart file as a parameter to the Call
.
Example
// Example image as Data
guard let jpeg = UIImageJPEGRepresentation(image, 0.7) else {
print("👿 not a valid jpeg")
return
}
// Create a multipart object and add it to the call
let multipart = MultipartFile(parameterName: "image", data: jpeg, mimeType: .jpeg)
let call = Call(path: "queries",
method: .POST,
parameter: [.multipart(multipart)])
// This assumes we have setup a singleton
let service = ServiceNoResponseData(call: call)
service.send {
do {
try $0()
} catch {
// handle error
}
}
Security is handeled by a FaroSecureURLSession. Every DeprecatedService
has a session that is by default FaroURLSession
.
If you want more security options you can Provide a Sublass of FaroSecureURLSession
or alternativaly implement the FaroSessionable
. To let Faro know about your session you need to provide it via the FaroSingleton
or for every instance of DeprecatedService
you made.
But first implement FaroSecureURLSession
.
Then add it to Faro
func setupFaroWithSecurity() {
let baseURL = "http://jsonplaceholder.typicode.com"
let sessionSessionDelegate = FaroURLSessionDelegate(allowUntrustedCertificates: false)
let secureSession = FaroSecureURLSession(urlSessionDelegate: sessionSessionDelegate)
FaroSingleton.setup(with: baseURL, session: secureSession)
// Example image as Data
guard let jpeg = UIImageJPEGRepresentation(image, 0.7) else {
print("👿 not a valid jpeg")
return
}
DeprecatedService(configuration: Configuration(baseURL: baseURL), faroSession: secureSession)
Faro is available through CocoaPods and the Swift Package Manager.
To install it with CocoaPods, add the following line to your Podfile:
pod "Faro"
Don’t think too hard, try hard!
More info on the contribution guidelines wiki page.
We follow the iCapps Coding guidelines.
We use Swiftlint to keep everything neat.
Faro is available under the MIT license. See the LICENSE file for more info.