The Restler framework has been built to use features of the newest versions of Swift. Inspiration for it is the Vapor library for building Server-side with Swift. What we love is functional programming, so you can build your desired request just calling some chained functions. The main goal of the framework is to provide a nice interface for making API requests the easiest as possible and the fastest as possible.
We think that README isn't a good place for complete documentation so that's why we decided to generate it to a folder inside the framework repository. Full documentation you can find in the Documentation folder. If you're looking for a description of a specific protocol or class, we put here a list of the most important symbols.
RestlerType - it's the main protocol which should be used when it comes to mocking or using Restler's class' instance.
- RestlerBasicRequestBuilderType - available for all HTTP methods.
- RestlerQueryRequestBuilderType - available for all HTTP methods.
- RestlerBodyRequestBuilderType - available for all HTTP methods.
- RestlerDownloadRequestBuilderType - available only for GET.
- RestlerMultipartRequestBuilderType - available only for POST.
- RestlerDecodableResponseRequestBuilderType - available for GET, POST, PUT, PATCH and DELETE (all without HEAD).
All these protocols are defined in one file: RestlerRequestBuilderType
Restler.Request - generic class for all request types provided by Restler.
- Restler.Error - errors returned by Restler.
- Restler.ErrorType - types which Restler can decode by himself. Every different type would be an
unknownError
.
- RestlerErrorParserType - a public protocol for the ErrorParser class.
- RestlerErrorDecodable - a protocol to implement if an object should be decoded by the ErrorParser.
Nothing is easier there - you just add the framework to the Swift Package Manager dependencies if you use one.
Otherwise you can use CocoaPods. If you use one simply add to your Podfile
:
...
pod 'Restler/Core'
...
It's important to specify it with /Core
! (Changed in v1.0)
and call in your console:
pod install
Import the framework to the project:
import RestlerCore
and call it!
If you don't want to add the same error to be parsed on a failure of every request, simply add the error directly to the error parser of the Restler object.
restler.errorParser.decode(ErrorToDecodeOnFailure.self)
If you don't want to decode it anymore, simply stop decoding it:
restler.errorParser.stopDecoding(ErrorToDecodeOnFailure.self)
Setting header values is very easy. Simply set it as a dictionary:
restler.header = [
.contentType: "application/json",
.cacheControl: "none",
"customKey": "value"
]
restler.header[.cacheControl] = nil
If you're using basic authentication in the "Authorization" key, simply provide username and password to the header:
restler.header.setBasicAuthentication(username: "me", password: "password")
Restler(baseURL: myBaseURL)
.get(Endpoint.myProfile) // 1
.query(anEncodableQueryObject) // 2
.failureDecode(ErrorToDecodeOnFailure.self) // 3
.setInHeader("myNewTemporaryToken", forKey: "token") // 4
.receive(on: .main) // 5
.decode(Profile.self) // 6
// 7
.subscribe(
onSuccess: { profile in // 8
updateProfile(with: profile)
},
onCompletion: { _ in // 9
hideLoadingIndicator()
})
- Makes GET request to the given endpoint.
- Encodes the object and puts it in query for the GET request.
- If an error will occur, an error parser would try to decode the given type.
- Sets the specified value for the given key in the header only for this request.
- Sets dispatch queue on which completion handlers will be called to the main queue.
- Decodes Profile object on a successful response. If it is not optional, a failure handler can be called.
- Since this moment we're operating on a request, not a request builder.
- A handler called if Restler would successfully end the request.
- A handler called on completion of the request whatever the result would be.
Restler(baseURL: myBaseURL)
.post(Endpoint.myProfile) // 1
.body(anEncodableQueryObject) // 2
.failureDecode(ErrorToDecodeOnFailure.self)
.decode(Profile.self)
.subscribe(
onFailure: { error in // 3
print("\(error)")
},
onCompletion: { _ in
hideLoadingIndicator()
})
- Makes POST request to the given endpoint.
- Encodes the object and puts it into the body of the request. Ignored if the selected request method doesn't support it.
- A handler called if the request has failed.
Any other method call is very similar to these two, but if you have questions simply create an issue.
- Restler approach:
Restler(baseURL: myBaseURL)
.get("/profile") // 1
.decode(Profile.self) // 2
.publisher // 3
.catch { _ in Empty() } // 4
.assign(to: \.profile, on: self) // 5
.store(in: &subscriptions) // 6
- Makes GET request to the given endpoint.
- Decode
Profile
object. - Convert the request object to publisher for easy using Combine in your code.
- Handle the thrown error
- Assign each element from a Publisher to a property on an object.
- Stores this type-erasing cancellable instance in the specified collection.
- More Combine approach:
Restler(baseURL: myBaseURL)
.get(Endpoint.myProfile) // 1
.query(anEncodableQueryObject) // 2
.publisher()? // 3
.receive(on: DispatchQueue.main) // 4
.map(\.data) // 5
.decode(type: Profile.self, decoder: JSONDecoder()) // 6
.catch { _ in Empty() } // 7
.assign(to: \.profile, on: self) // 8
.store(in: &subscriptions) // 9
- Makes GET request to the given endpoint.
- Encodes the object and puts it in query for the GET request.
- Builds a request and returns publisher for Combine support.
- Specifies the scheduler on which to receive elements from the publisher. In this case the main queue.
- Get Data object from
DataTaskPublisher
. - Decode
Profile
object. - Handle the error
- Assigns each element from a Publisher to a property on an object.
- Stores this type-erasing cancellable instance in the specified collection.
First of all, you need to add RxRestler
to your target you can do it simply in SPM. In CocoaPods you should add to your Podfile:
pod `Restler/Rx`
Then import RxRestler
to every file it's needed.
Restler(baseURL: myBaseURL)
.get(Endpoint.myProfile)
.query(anEncodableQueryObject)
.receive(on: .main) // 1
.decode(Profile.self) // 2
.rx // 3
.subscribe( // 4
onSuccess: { print("This is my profile:", $0) },
onError: { print("This is an error:", $0) })
.disposed(by: bag) // 5
- Subscribe handlers will be called on the provided queue even if it's done with RxSwift (setting a scheduler with this property set may cause some little delay between receiving a response and handling it but the handlers will be called on the provided scheduler).
- Decode some type on successful response - Void, Data, or some custom object.
- Move request to Rx usage. This returns
Single<Profile>
in this case. - Here we call already the RxSwift function.
- Remember about adding the
Disposable
to theDisposeBag
. The networking task will be canceled automatically if thebag
will deinitialize.
If you want to contribute in this framework, simply put your pull request here.
If you have found any bug, file it in the issues.
If you would like Restler to do something else, create an issue with a feature request.
- Clone the project and open the project's folder in the terminal.
- Run a configuration script:
./Scripts/configure.sh
- Fill configuration file in folder
Restler-Example/Restler-Example/Configuration
namedDebug.xcconfig
with needed information. - Open the project in the folder
Restler-Example
. You can do it from the terminal:open Restler-Example/Restler-Example.xcodeproj
- Run tests to be sure everything works properly.
Run command ./Scripts/pod_lib_lint.rb Restler.podspec
to lint the podspec before pushing changes to the repo.
- Open the project root directory.
cd Scripts/releaseTool
swift run ReleaseTool release ../..