Lightweight network abstraction layer, written on top of Alamofire

Overview

CI codecov.io CocoaPod platform CocoaPod version Swift Package Manager compatible Packagist

TRON is a lightweight network abstraction layer, built on top of Alamofire. It can be used to dramatically simplify interacting with RESTful JSON web-services.

Features

  • Generic, protocol-based implementation
  • Built-in response and error parsing
  • Support for any custom mapper (SwiftyJSON implementation provided). Defaults to Codable protocol.
  • Support for upload tasks
  • Support for download tasks and resuming downloads
  • Robust plugin system
  • Stubbing of network requests
  • Modular architecture
  • Support for iOS/Mac OS X/tvOS/watchOS/Linux
  • Support for CocoaPods/Swift Package Manager
  • RxSwift extension
  • Complete documentation

Overview

We designed TRON to be simple to use and also very easy to customize. After initial setup, using TRON is very straightforward:

let request: APIRequest<User,APIError> = tron.codable.request("me")
request.perform(withSuccess: { user in
  print("Received User: \(user)")
}, failure: { error in
  print("User request failed, parsed error: \(error)")
})

Requirements

  • Xcode 10 and higher
  • Swift 4 and higher
  • iOS 10 / macOS 10.12 / tvOS 10.0 / watchOS 3.0

Installation

Swift Package Manager(requires Xcode 11)

  • Add package into Project settings -> Swift Packages

TRON framework includes Codable implementation. To use SwiftyJSON, import TRONSwiftyJSON framework. To use RxSwift wrapper, import RxTRON.

CocoaPods

pod 'TRON', '~> 5.3.0'

Only Core subspec, without SwiftyJSON dependency:

pod 'TRON/Core', '~> 5.3.0'

RxSwift extension for TRON:

pod 'TRON/RxSwift', '~> 5.3.0'

Migration Guides

Project status

TRON is under active development by MLSDev Inc. Pull requests are welcome!

Request building

TRON object serves as initial configurator for APIRequest, setting all base values and configuring to use with baseURL.

let tron = TRON(baseURL: "https://api.myapp.com/")

You need to keep strong reference to TRON object, because it holds Alamofire.Manager, that is running all requests.

URLBuildable

URLBuildable protocol is used to convert relative path to URL, that will be used by request.

public protocol URLBuildable {
    func url(forPath path: String) -> URL
}

By default, TRON uses URLBuilder class, that simply appends relative path to base URL, which is sufficient in most cases. You can customize url building process globally by changing urlBuilder property on TRON or locally, for a single request by modifying urlBuilder property on APIRequest.

Sending requests

To send APIRequest, call perform(withSuccess:failure:) method on APIRequest:

let alamofireRequest = request.perform(withSuccess: { result in }, failure: { error in})

Alternatively, you can use performCollectingTimeline(withCompletion:) method that contains Alamofire.Response inside completion closure:

request.performCollectingTimeline(withCompletion: { response in
    print(response.timeline)
    print(response.result)
})

In both cases, you can additionally chain Alamofire.Request methods, if you need:

request.perform(withSuccess: { result in }, failure: { error in }).progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
    print(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)
}

Response parsing

Generic APIRequest implementation allows us to define expected response type before request is even sent. On top of Alamofire DataResponseSerializerProtocol, we are adding one additional protocol for error-handling.

public protocol DataResponseSerializerProtocol {
    associatedtype SerializedObject

    public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Self.SerializedObject
}

public protocol ErrorSerializable: Error {
    init?(serializedObject: Any?, request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?)
}

Codable

Parsing models using Swift4 Codable protocol is simple, implement Codable protocol:

struct User: Codable {
  let name : String
  let id: Int
}

And send a request:

let request: APIRequest<User,APIError> = tron.codable.request("me")
request.perform(withSuccess: { user in
  print("Received user: \(user.name) with id: \(user.id)")
})

It's possible to customize decoders for both model and error parsing:

let userDecoder = JSONDecoder()

let request : APIRequest<User,APIError> = tron.codable(modelDecoder: userDecoder).request("me")

JSONDecodable

TRON provides JSONDecodable protocol, that allows us to parse models using SwiftyJSON:

public protocol JSONDecodable {
    init(json: JSON) throws
}

To parse your response from the server using SwiftyJSON, all you need to do is to create JSONDecodable conforming type, for example:

class User: JSONDecodable {
  let name : String
  let id: Int

  required init(json: JSON) {
    name = json["name"].stringValue
    id = json["id"].intValue
  }
}

And send a request:

let request: APIRequest<User,MyAppError> = tron.swiftyJSON.request("me")
request.perform(withSuccess: { user in
  print("Received user: \(user.name) with id: \(user.id)")
})

There are also default implementations of JSONDecodable protocol for Swift built-in types like String, Int, Float, Double and Bool, so you can easily do something like this:

let request : APIRequest<String,APIError> = tron.swiftyJSON.request("status")
request.perform(withSuccess: { status in
    print("Server status: \(status)") //
})

You can also use Alamofire.Empty struct in cases where you don't care about actual response.

Some concepts for response serialization, including array response serializer, are described in Container Types Parsing document

It's possible to customize JSONSerialization.ReadingOptions, that are used by SwiftyJSON.JSON object while parsing data of the response:

let request : APIRequest<String, APIError> = tron.swiftyJSON(readingOptions: .allowFragments).request("status")

RxSwift

let request : APIRequest<Foo, APIError> = tron.codable.request("foo")
_ = request.rxResult().subscribe(onNext: { result in
    print(result)
})
let multipartRequest : UploadAPIRequest<Foo,APIError> = tron.codable.uploadMultipart("foo", formData: { _ in })
multipartRequest.rxResult().subscribe(onNext: { result in
    print(result)
})

Error handling

TRON includes built-in parsing for errors. APIError is an implementation of ErrorSerializable protocol, that includes several useful properties, that can be fetched from unsuccessful request:

request.perform(withSuccess: { response in }, failure: { error in
    print(error.request) // Original URLRequest
    print(error.response) // HTTPURLResponse
    print(error.data) // Data of response
    print(error.fileURL) // Downloaded file url, if this was a download request
    print(error.error) // Error from Foundation Loading system
    print(error.serializedObject) // Object that was serialized from network response
  })

CRUD

struct Users
{
    static let tron = TRON(baseURL: "https://api.myapp.com")

    static func create() -> APIRequest<User,APIError> {
      return tron.codable.request("users").post()
    }

    static func read(id: Int) -> APIRequest<User, APIError> {
        return tron.codable.request("users/\(id)")
    }

    static func update(id: Int, parameters: [String:Any]) -> APIRequest<User, APIError> {
      return tron.codable.request("users/\(id)").put().parameters(parameters)
    }

    static func delete(id: Int) -> APIRequest<User,APIError> {
      return tron.codable.request("users/\(id)").delete()
    }
}

Using these requests is really simple:

Users.read(56).perform(withSuccess: { user in
  print("received user id 56 with name: \(user.name)")
})

It can be also nice to introduce namespacing to your API:

enum API {}
extension API {
  enum Users {
    // ...
  }
}

This way you can call your API methods like so:

API.Users.delete(56).perform(withSuccess: { user in
  print("user \(user) deleted")
})

Stubbing

Stubbing is built right into APIRequest itself. All you need to stub a successful request is to set apiStub property and turn stubbingEnabled on:

API.Users.get(56)
         .stub(with: APIStub(data: User.fixture().asData))
         .perform(withSuccess: { stubbedUser in
           print("received stubbed User model: \(stubbedUser)")
})

Stubbing can be enabled globally on TRON object or locally for a single APIRequest. Stubbing unsuccessful requests is easy as well:

API.Users.get(56)
         .stub(with: APIStub(error: CustomError()))
         .perform(withSuccess: { _ in },
                  failure: { error in
  print("received stubbed api error")
})

You can also optionally delay stubbing time:

request.apiStub.stubDelay = 1.5

Upload

  • From file:
let request = tron.codable.upload("photo", fromFileAt: fileUrl)
  • Data:
let request = tron.codable.upload("photo", data: data)
  • Stream:
let request = tron.codable.upload("photo", fromStream: stream)
  • Multipart-form data:
let request: UploadAPIRequest<EmptyResponse,MyAppError> = tron.codable.uploadMultipart("form") { formData in
    formData.append(data, withName: "cat", mimeType: "image/jpeg")
}
request.perform(withSuccess: { result in
    print("form sent successfully")
})

Download

let responseSerializer = TRONDownloadResponseSerializer { _,_, url,_ in url }
let request: DownloadAPIRequest<URL?, APIError> = tron.download("file",
                                                                to: destination,
                                                                responseSerializer: responseSerializer)

Plugins

TRON includes plugin system, that allows reacting to most of request events.

Plugins can be used globally, on TRON instance itself, or locally, on concrete APIRequest. Keep in mind, that plugins that are added to TRON instance, will be called for each request. There are some really cool use-cases for global and local plugins.

By default, no plugins are used, however two plugins are implemented as a part of TRON framework.

NetworkActivityPlugin

NetworkActivityPlugin serves to monitor requests and control network activity indicator in iPhone status bar. This plugin assumes you have only one TRON instance in your application.

let tron = TRON(baseURL: "https://api.myapp.com", plugins: [NetworkActivityPlugin()])

NetworkLoggerPlugin

NetworkLoggerPlugin is used to log responses to console in readable format. By default, it prints only failed requests, skipping requests that were successful.

Local plugins

There are some very cool concepts for local plugins, some of them are described in dedicated PluginConcepts page.

Alternatives

We are dedicated to building best possible tool for interacting with RESTful web-services. However, we understand, that every tool has it's purpose, and therefore it's always useful to know, what other tools can be used to achieve the same goal.

TRON was heavily inspired by Moya framework and LevelUPSDK, which is no longer available in open-source.

License

TRON is released under the MIT license. See LICENSE for details.

About MLSDev

MLSDev.com

TRON is maintained by MLSDev, Inc. We specialize in providing all-in-one solution in mobile and web development. Our team follows Lean principles and works according to agile methodologies to deliver the best results reducing the budget for development and its timeline.

Find out more here and don't hesitate to contact us!

Comments
  • Passing Paramenter in Tron Request

    Passing Paramenter in Tron Request

    hi with TRON - > how to use this URL (https://www.sampledomain/Device/GetFeature?token=f6b8a88b-6939-4bd6-a3f6-589020beb35d&PageNo&MQ==&PageSize=MTA=)

    question 
    opened by iehsan77 11
  • SwiftyJSON Array extension

    SwiftyJSON Array extension

    Is there any reason why the array extension of JSONDecodable is commented since the last update? https://github.com/MLSDev/TRON/blob/master/Source/SwiftyJSON/SwiftyJSONDecodable.swift#L58

    enhancement 
    opened by Nonouf 10
  • Is XML Based Response Supported

    Is XML Based Response Supported

    I've been trying to utilize TRON for an API that gives response in XML and my response has been empty always. This is how I've been making my requests:

    let tron = MoviepathService.create()
        
        func getSubscriptions(params: [String : Any]) -> Observable<[SubscriptionObject]> {
            let request: APIRequest<String, MoviePathError> = tron.request("".getSubscriptions())
            request.method = .post
            request.headers = ["Content-Type":"application/x-www-form-urlencoded"]
            request.parameters = params
            return request.rxResult().flatMap({ (element) -> Observable<[SubscriptionObject]> in
                print("SubscriptionFetch: ", element)
                return Observable.just([SubscriptionObject]())
            })
        }
    

    Am I doing anything wrong? Thanks.

    question 
    opened by tonespy 8
  • setting http headers isn't working

    setting http headers isn't working

    I am using Xcode 8.3.3, TRON, Alamofire, SwiftyJSON. I need to set my headers to ["Content-Type":"application/json"], I have tried both of the following:

    request.headers = ["Content-Type":"application/json"] and let headers = request.headerBuilder.headers(forAuthorizationRequirement: AuthorizationRequirement.required, including: ["Content-Type":"application/json"]) request.headers = headers

    neither of these options seems to make a difference, I still get a 400 or 405 server error and the logs show that the header is still: ["Accept":"application/json"], which I believe is the default according to the documentation.

    Maybe I am misreading the docs and am trying to set the headers incorrectly. Can anyone help or have any suggestions.

    Thanks in advanced, Jonathan

    question 
    opened by jonathan3087 8
  • Setting request timeout

    Setting request timeout

    I have a static instance of TRON (tron). I tried the following to set the timeout to 10 seconds.

    tron.manager.session.configuration.timeoutIntervalForRequest = 10
    tron.manager.session.configuration.timeoutIntervalForResource = 10
    

    I also tried overriding the Alamofire manager, but it's a let variable anyway. Any suggestion about that ?

    enhancement 
    opened by ilkerc 8
  • the error when fetching some json file

    the error when fetching some json file

    When using TRON to fetch the json file: "https://letsbuildthatapp-videos.s3-us-west-2.amazonaws.com/kindle.json", there is an error occurred but the response code is still 200. Nonetheless, if I used the URLSession.shared.dataTask() instead, the json file is transmitted correctly.

    Te-Jen Wu [email protected]

    question 
    opened by wtj123 7
  • request.perform fails despite Model being initialized with the desired json

    request.perform fails despite Model being initialized with the desired json

    What did you do?

    let request: APIRequest<Home, JSONError> = tron.swiftyJSON.request("/twitter/home")
     request.perform(withSuccess: { (home) in
                print("Fetched json objects")
                print(home.users.count)
    
            }) { ("Failed to fetch json, ", err) in
    
                print(err)
            }
    

    What did you expect to happen?

    I expected the request to be successful and home.users.count to be printed. Especially because upon initialization of the home object, it successfully prints the desired json.

    If it would fail, which it shouldn't, I expected the fail closure to give me information on the error (I'd think it would print eg. the error and response variables that the ErrorSerializable-conforming object err should have.

    What happened instead?

    I got this error: Failed to fetch json, Projectname.HomeDatasourceController.JSONError

    TRON Environment

    TRON version: 5.0.0-beta.1' Xcode version: 10.2 Swift version: 5 Platform(s) running TRON: macOS version running Xcode: 10.14.3

    Demo Project or sample code

    ASAP

    enhancement question 
    opened by lk251 6
  • Submitting JSON as body?

    Submitting JSON as body?

    I'm trying to submit a JSON post to my local dev server and having issues. I haven't seen much documentation on sending complex parameters or JSON in the body for a POST request in the documentation (unless I'm missing something). I've been browsing through issues with no success unfortunately on how to get this to work, I have a complex bit of JSON that I need to send in a .POST request to my Rails API. Here is the code for sending the JSON

     `@IBAction func SessionSubmit(_ sender: Any) {
        let selected_session_type = session_type_ids[self.SessionTypePicker.selectedRow(inComponent: 0)]
        let selected_session_duration = session_type_durations[self.SessionTypePicker.selectedRow(inComponent: 0)]
        let dateFormatter = DateFormatter()
        let selected_start_time = DateTimePicker.date
        let start_time = dateFormatter.string(from: DateTimePicker.date)
        let end_time = dateFormatter.string(from: selected_start_time + selected_session_duration.minutes)
        let refreshToken = current_user.refreshToken as String
        let accessToken = current_user.accessToken as String
        let params: [String: Any] = ["access_token": accessToken, "refresh_token": refreshToken]
        let body: [String: Any] = ["data": [
                        "type": "session",
                        "attributes": [
                            "title": "",
                            "description": "",
                            "start": start_time,
                            "end": end_time,
                            "session_mode": "video_session"],
                            "relationships": [
                                "users": [
                                    "data": [
                                        ["type": "user",
                                         "id": current_user.userId],
                                        ["type": "user",
                                         "id": clientId]
                                    ]
                                ],
                                "session_type":[
                                    "data": [
                                        "type": "session_type",
                                        "id": selected_session_type
                                        ]
                                    ]
                                ]
                            ]
                        ]
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: body, options: .prettyPrinted)
            print(jsonData)
            let decoded = try JSONSerialization.jsonObject(with: jsonData, options: [])
            print(decoded)
            
            if let dictFromJSON = decoded as? [String:Any] {
                print(dictFromJSON)
                self.sendData(parameters: params, body: dictFromJSON) {
                    self.stopAnimating()
                }
            }
        } catch {
            print(error.localizedDescription)
        }
        startAnimating(GlobalVariables().LoadingSize)`
    
       `    func sendData(parameters: [String:Any], body: [String:Any], finished: @escaping () -> Void) {
        DataController().Post(parameters: parameters, path: "/v1/sessions/"+current_user.userId).perform(withSuccess: { (FetchedArray) in
            if let SessionTypesArray = FetchedArray.response["data"].array {
                self.session_types += SessionTypesArray 
            }
            finished()
        }) { (FetchFailed) in
            AuthenticationController().logout(user: self.current_user)
            self.dismiss(animated: true, completion: {});
            finished()
        }
    }`
    

    I'm thinking maybe I need to make these embedded in the document and only have my refresh and access tokens as parameters? so I tried working on doing it that way and yet still another road block because of not seeing any ways to add to the body, I know there is appendBody but I'm not sure how that would work either, the json seems to not be flowing to the rails api correctly either `Started POST "/v1/sessions/122" for 127.0.0.1 at 2017-05-19 13:52:32 -0400 Error occurred while parsing request parameters. Contents:

    access_token=90d2befd58912f978dc681f2f0d1eaf3d217dbe25fdac3d1ec4ab45e9bfff41a&data%5Btype%5D=session&data%5Battributes%5D%5Bdescription%5D=&data%5Battributes%5D%5Btitle%5D=&data%5Battributes%5D%5Bend%5D=&data%5Battributes%5D%5Bsession_mode%5D=video_session&data%5Battributes%5D%5Bstart%5D=&data%5Brelationships%5D%5Bsession_type%5D%5Bdata%5D%5Btype%5D=session_type&data%5Brelationships%5D%5Bsession_type%5D%5Bdata%5D%5Bid%5D=379&data%5Brelationships%5D%5Busers%5D%5Bdata%5D%5B%5D%5Btype%5D=user&data%5Brelationships%5D%5Busers%5D%5Bdata%5D%5B%5D%5Bid%5D=122&data%5Brelationships%5D%5Busers%5D%5Bdata%5D%5B%5D%5Btype%5D=user&data%5Brelationships%5D%5Busers%5D%5Bdata%5D%5B%5D%5Bid%5D=6&refresh_token=6b60a52534e1fa2ed436a9542a6c27b7f05e56e7b306f48df12b286b8fe5f624

    JSON::ParserError - 822: unexpected token at 'access_token=90d2befd58912f978dc681f2f0d1eaf3d217dbe25fdac3d1ec4ab45e9bfff41a&data%5Btype%5D=session&data%5Battributes%5D%5Bdescription%5D=&data%5Battributes%5D%5Btitle%5D=&data%5Battributes%5D%5Bend%5D=&data%5Battributes%5D%5Bsession_mode%5D=video_session&data%5Battributes%5D%5Bstart%5D=&data%5Brelationships%5D%5Bsession_type%5D%5Bdata%5D%5Btype%5D=session_type&data%5Brelationships%5D%5Bsession_type%5D%5Bdata%5D%5Bid%5D=379&data%5Brelationships%5D%5Busers%5D%5Bdata%5D%5B%5D%5Btype%5D=user&data%5Brelationships%5D%5Busers%5D%5Bdata%5D%5B%5D%5Bid%5D=122&data%5Brelationships%5D%5Busers%5D%5Bdata%5D%5B%5D%5Btype%5D=user&data%5Brelationships%5D%5Busers%5D%5Bdata%5D%5B%5D%5Bid%5D=6&refresh_token=6b60a52534e1fa2ed436a9542a6c27b7f05e56e7b306f48df12b286b8fe5f624': json (1.8.6) lib/json/common.rb:155:in parse'

    any help here would be greatly appreciated guys! thanks in advance!

    opened by justindunn 6
  • Help needed with json response erroring when 200 code response

    Help needed with json response erroring when 200 code response

    I saw a related issue to this problem i'm having already in the closed issues, but the fixes there didn't do the trick for me. I'm getting a json response and without error from my server (200 code) but i'm getting an error from xcode/swift. Below is said error:

    { status code: 200, headers { "Cache-Control" = "max-age=0, private, must-revalidate"; Connection = close; "Content-Type" = "application/json; charset=utf-8"; Etag = "W/\"f49d10c019a7a3b8c095a8da43570f5f\""; Server = thin; "X-Content-Type-Options" = nosniff; "X-Frame-Options" = SAMEORIGIN; "X-Meta-Request-Version" = "0.3.4"; "X-Request-Id" = "129f985f-31a5-4fe7-a09b-3e8d0cb4823a"; "X-Runtime" = "0.433514"; "X-XSS-Protection" = "1; mode=block"; } }), data: Optional(653 bytes), error: Optional(Alamofire.AFError.responseValidationFailed(Alamofire.AFError.ResponseValidationFailureReason.unacceptableContentType(acceptableContentTypes: ["application/vnd.api+json"], responseContentType: "application/json"))), errorModel: Optional(wecounsel.DataController.FetchFailed))

    Here is what the json looks like:

    { "meta" : { "current_user_abilities" : { "facilitator" : false, "provider" : true, "consumer" : false, "org_admin" : false, "admin" : false } }, "data" : [ { "id" : "session-4763-20170422123000", "links" : { "self" : "http:\/\/localhost:3000\/v1\/sessions\/4763\/repeated\/starts\/2017-04-22%2012:30:00%20-0400\/ends\/2017-04-22%2013:30:00%20-0400" }, "type" : "session", "attributes" : { "end" : "2017-04-22 13:30:00", "start" : "2017-04-22 12:30:00", "title" : "Session", "current_user_participates" : true, "description" : "<p>Session with Doc Brown and Austin Consumer for Follow up.<\/p><p>12:30 PM - 01:30 PM EDT<\/p>", "repeat_instance" : true, "session_mode" : "video_session" } } ] }

    Here is my functions I'm using:

    ` public class DataController { static let tron = TRON(baseURL: GlobalVariables().baseURL)

    class Fetched: JSONDecodable {
        let response: JSON
        required init(json: JSON) throws {
            let response = json
            self.response = response
        }
    }
    
    class FetchFailed: JSONDecodable {
        let response: JSON
        required init(json: JSON) throws {
            print(json)
            let response = json
            self.response = response
    }
    
    func Get(parameters: [String:Any], path: String) -> APIRequest<Fetched, FetchFailed> {
        let request: APIRequest<Fetched, FetchFailed> = DataController.tron.request(path)
        request.parameters = parameters
        request.headers = ["Accept":"application/vnd.api+json"]
    

    // DataController.tron.headerBuilder = HeaderBuilder(defaultHeaders: [:]) return request }`

    func getData(parameters: [String:Any], finished: @escaping () -> Void) { DataController().Get(parameters: parameters, path: "/v1/calendar").perform(withSuccess: { (Fetched) in if let eventsArray = Fetched.response["data"].array { self.events += eventsArray } print(self.events, "here are the events") finished() }) { (FetchFailed) in print(FetchFailed) finished() } }

    anyone have any idea of whats going on? i know the json has an array but i don't think thats the issue is it?

    opened by justindunn 6
  • Unable To Use The Dependency On Xcode 9-beta

    Unable To Use The Dependency On Xcode 9-beta

    I am using Xcode 9-Beta for development. And I've not been able to utilize the TRON library. Most of the errors are coming from the Alamofire library. I could modify the libraries to work, but it's a project being worked on by more than one person. So, is there a way to have this fixed or I've to go migrate my codebase back to 3.1?

    I installed Alamofire 4.4 and it's working fine. But, the one bundled with TRON is failing when building.

    Thanks

    enhancement 
    opened by tonespy 5
  • Compatible error with xcode 8.2.1

    Compatible error with xcode 8.2.1

    When I tried to install Tron, it shows me this message in XCode :

    “Use Legacy Swift Language Version” (SWIFT_VERSION) is required to be configured correctly for targets which use Swift. Use the [Edit > Convert > To Current Swift Syntax…] menu to choose a Swift version or use the Build Settings editor to configure the build setting directly.

    As Mentioned I'm using XCode Version 8.2.1 & Cocoapods 'TRON', '~> 2.0.0' The different is, version of Alamofire was (4.2.0)in that time TRON was working fine, but for current version Alamofire (4.4.0) showing me mentioned error

    opened by ghost 5
Releases(5.5.0-beta.1)
  • 5.5.0-beta.1(Jul 18, 2022)

    Introducing support for Swift Concurrency

    let request: APIRequest<Int,APIError> = tron.codable
        .request("status/200")
    
    let result = try await request.sender().value
    

    Swift Concurrency methods require Swift 5.5 / Xcode 13.2 / iOS 13 / tvOS 13 / macOS 10.15 / watchOS 6.

    Read more usage examples in README.

    Added

    • download(_:to:) and download(_:to:resumingFrom:) methods that create DownloadAPIRequest with <URL, ErrorModel> generic constraints to simplify requests creation, where you need only URL from resulting operation.
    • Structured Concurrency support for Swift 5.5 and higher: RequestSender, DownloadRequestSender types.

    Fixed

    • Issue, that could lead to sending network request with api stubs enabled, but Session.startRequestsImmediately property was set to false.

    Breaking

    • New deployment targets: iOS 11 / tvOS 11 / macOS 10.13 / watchOS 4 / Xcode 13. OS deployment targets now match minimum deployment targets, supported by Xcode 14.
    Source code(tar.gz)
    Source code(zip)
  • 5.4.1(May 28, 2021)

  • 5.4.0(Jan 4, 2021)

  • 5.3.0(Oct 22, 2020)

    Added

    • Ability to modify URLRequests before it's adapted and sent:
    tron.codable
        .request("status")
        .modifyRequest { $0.httpShouldHandleCookies = false }
    

    This feature uses Alamofire.RequestModifier closure, that can also be set without DSL on request instance directly:

    let request : APIRequest<Post,Empty> = tron.codable.request("posts")
    request.requestModifier = { urlRequest in
        urlRequest.httpShouldHandleCookies = false
    }
    
    Source code(tar.gz)
    Source code(zip)
  • 5.2.0(Aug 11, 2020)

    Added

    • Combine support on supported platforms through publisher() method on APIRequest, UploadAPIRequest, DownloadAPIRequest.
    • APIError.isCancelled property, that tells, whether request, that errored, was cancelled by sender.

    Changed

    • Alamofire.ParameterEncoding, JSONEncoding and URLEncoding are now exposed through TRON API and don't require importing Alamofire to use.

    Deprecated

    • NetworkActivityPlugin is deprecated on iOS 13 and higher, because UIApplication.isNetworkActivityIndicatorVisible property it has been switching is deprecated on iOS 13 and higher.
    Source code(tar.gz)
    Source code(zip)
  • 5.1.0(May 4, 2020)

    Changed

    • Several Alamofire types that are exposed through TRON API's are now implicitly exported to allow using them without needing to write import Alamofire. See Exports.swift file for a list of them.
    Source code(tar.gz)
    Source code(zip)
  • 5.0.3(Apr 6, 2020)

    Added

    • FileURLPassthroughResponseSerializer, which can be used as a response serializer for DownloadAPIRequest when you are only interested in URL of downloaded file.

    Fixed

    • NetworkLoggerPlugin now correctly skips cancelled requests
    Source code(tar.gz)
    Source code(zip)
  • 5.0.2(Mar 19, 2020)

  • 5.0.1(Mar 10, 2020)

    • BaseRequest.headers now default to HTTPHeaders.default to allow sending Alamofire default headers such as "Accept-Language", "Accept-Encoding", "User-Agent".
    Source code(tar.gz)
    Source code(zip)
  • 5.0.0-rc.1(Sep 6, 2019)

    Added

    • Better debug prints for NetworkLoggerPlugin when decoding using Codable protocol.
    • configure(_:) method for BaseRequest DSL to allow configuring request with several changes at once.

    Breaking

    • Plugin API that previously was called with Alamofire.Data/DownloadResponse<Model, Error> is now called with Alamofire.Data/DownloadResponse<Model, AFError> due to Alamofire changes to error handling.
    • performCollectingTimeline(withCompletion:) method is now called also with AFError instead of Error.
    Source code(tar.gz)
    Source code(zip)
  • 5.0.0-beta.5(Jun 28, 2019)

    Added

    • Support for per-request Interceptors.
    • Three different behaviors for building URLs: .appendingPathComponent, .relativeToBaseURL and .custom. Those can be set in TRON initializer:
    let tron = TRON(baseURL: "https://www.example.com/", buildingURL: .relativeToBaseURL)
    

    Or you can change URLBuilder.Behavior on per-request basis, using the new DSL:

    let request: APIRequest<Int,APIError> = tron.swiftyJSON
        .request("status/200")
        .buildURL(.relativeToBaseURL)
    

    Default behavior for TRON is .appendingPathComponent.

    Removed

    • URLBuildable protocol. Please use different behaviors for URLBuilder instead.
    Source code(tar.gz)
    Source code(zip)
    TRON.framework.zip(37.99 MB)
  • 5.0.0-beta.4(Jun 16, 2019)

    Added

    • Support for Swift Package Manager in Xcode 11
    • New convenient DSL, that allows to convert this code:
    func deleteSession() -> APIRequest<Empty, UnknownError> {
        let request : APIRequest<Empty, UnknownError> = tron.codable.request("session")
        request.method = .delete
        return request
    }
    

    into:

    func deleteSession() -> APIRequest<Empty, UnknownError> {
        return tron.codable.request("session").delete()
    }
    

    Read more about other DSL improvements in 5.0 Migration Guide

    Changed

    • URLBuilder now resolves URL's using URL(string:relativeTo:) method, thus allowing more flexible url creation.
    Source code(tar.gz)
    Source code(zip)
  • 5.0.0-beta.3(May 17, 2019)

    Added

    • Ability to traverse json to any level when using SwiftyJSONDecodable.

    Changed

    • Improved response serializer behavior for cases where requests were stubbed using URLProtocol.
    • TRON 5 requires RxSwift 5 and SwiftyJSON 5
    • Core is now a default subspec for CocoaPods installation method. To use SwiftyJSON, add following to Podfile:
    pod 'TRON/SwiftyJSON'
    
    Source code(tar.gz)
    Source code(zip)
    TRON.framework.zip(38.71 MB)
  • 4.2.2(Apr 8, 2019)

  • 5.0.0-beta.2(Apr 6, 2019)

    Changed

    • ErrorSerializable protocol changed to have non-optional initializer and to not accept serializedObject. It no longer can be used for additional object validation, but behavior should be more predictable and straightforward - ErrorSerializable should only be created if somebody (URL loading system, Alamofire or Model serialization) actually reported error.
    • codable is now a lazy stored property instead of computed property.
    • CodableSerializer API has been made open to allow easy customization in subclasses.
    • NetworkLoggerPlugin now has a constructor that allows to easily configure it's behavior.

    Breaking

    • Properties that worked with Alamofire.SessionManager have been renamed to session to be in line with Alamofire renaming of SessionManager to Session.

    Removed

    • TRON.defaultAlamofireManager() method. TRON initializer now uses Alamofire.Session.default as a replacement.
    • TRON.processingQueue property
    Source code(tar.gz)
    Source code(zip)
  • 5.0.0-beta.1(Mar 12, 2019)

    TRON now requires:

    • Xcode 10
    • Swift 4 and higher
    • iOS/tvOS 10 and higher
    • watchOS 3 and higher
    • macOS 10.12 and higher

    Added

    • Complete documentation
    • TRONDataResponseSerializer and TRONDownloadResponseSerializer structs to encapsulate serialization of responses using closure.
    • All test suite now uses StubbingURLProtocol to stop tests from sending network requests. Closes #21.
    • Additional JSONDecodable conformances have been added for arithmetic types such as Int8...Int64, UInt8...64.

    Removed

    • EmptyResponse type was replaced with Alamofire.Empty struct to not interfere with Alamofire.EmptyResponse protocol.
    • TRON.stubbingShouldBeSuccessful property since now each stub directly defines it's behavior instead of global setting
    • Conditional conformance of Array to JSONDecodable
    • Convenience download methods on CodableSerializer and JSONDecodableSerializer
    • AuthorizationRequirement enum. Please use Alamofire.RequestAdapter and Session.adapter property to adapt request, when additional headers are needed.
    • HeaderBuildable protocol and HeaderBuilder types. Please use BaseRequest.headers property of type Alamofire.HTTPHeaders directly.
    • ErrorHandlingDataResponseSerializerProtocol and ErrorHandlingDownloadResponseSerializer protocol. Now, ErrorModel on all requests conforms to ErrorSerializable protocol, that contains initializer that allows to create it directly.
    • CodableDownloadParser and JSONDecodableDownloadParser, replacement class DownloadSerializer has been introduced, it allows to create a data model by implementing DownloadResponseSerializerProtocol

    Breaking

    • headers property of BaseRequest now contains HTTPHeaders type instead of [String: String]. Please note that along with HeaderBuilder removal TRON no longer sends 'Accept':'application/json' header by default.
    • APIError is changed to be able to accept SerializedObject and is now a class with nullable initializer. Also, DownloadAPIError type has been introduced for download errors, that do not have Data in them, but have fileURL instead.
    • Plugin methods that previously accepted APIError<ErrorModel> now accept ErrorModel directly. Added didSuccessfullyParseDownloadResponse and didReceiveDownloadResponse methods.
    • All concrete implementations of DataResponseSerializerProtocol such as CodableParser and JSONDecodableParser now have only one generic argument - Model and are only parsing model type.
    • JSONDecodableParser and CodableParser now have only one generic argument - Model, since ErrorModel is now moved to ErrorSerializable protocol, that does not depend on any particular serializer.
    • APIStub has been rewritten from scratch to allow injecting only results of network request(URLRequest, HTTPURLResponse, Data, Error and fileURL) as opposed to actual Model and errorModel as well as definition of successful/unsuccessful requests. APIStub now is been attached to Alamofire.Request when stubbing for this particular request has been enabled. Rewrite also allows plugin callbacks to be called more consistently for both stubbed and unstubbed cases.
    • rxMultipartResult method on UploadRequest method was removed since UploadRequest for multipart requests in Alamofire 5 is now synchronous and now does not require special handling. You can now call rxResult replacement method instead.
    Source code(tar.gz)
    Source code(zip)
  • 4.2.0(Apr 12, 2018)

  • 4.1.2(Feb 27, 2018)

  • 4.1.1(Feb 27, 2018)

  • 4.1.0(Dec 28, 2017)

  • 4.0.0(Nov 15, 2017)

  • 4.0.0-beta.2(Sep 29, 2017)

    • RxSwift dependency is bumped up to 4.0.0-beta.0, SwiftyJSON dependency is bumped to 4.0.0-alpha.1
    • Binary release is compiled with Xcode 9.0 Swift 4 compiler.
    • Added ability to customize JSONSerialization.ReadingOptions for JSONDecodableSerializer. Unlike previous releases, no options are specified by default(Previously SwiftyJSON used allowFragments option).

    To have old behavior that allows fragmented json, use:

    let request = tron.swiftyJSON(readingOptions: .allowFragments).request("path")
    
    • Added ability to customize JSONDecoder for CodableSerializer for both model parsing and error parsing.
    • CodableParser and JSONDecodableParser are now classes, that are subclassible.
    Source code(tar.gz)
    Source code(zip)
    TRON.framework.zip(39.78 MB)
  • 4.0.0-beta.1(Sep 10, 2017)

    This is major release, containing breaking API changes, please read TRON 4.0 Migration Guide

    • Implemented support for Codable protocol.
    • APIError now takes it's localizedDescription from underlying errorModel if that model is LocalizedError, and from error.localizedDescription if not.

    Breaking changes

    • SwiftyJSONDecodable methods are now prefixed with .swiftyJSON, like so:
    // old
    let request = tron.request("path")
    // new
    let request = tron.swiftyJSON.request("path")
    
    Source code(tar.gz)
    Source code(zip)
    TRON.framework.zip(36.14 MB)
  • 3.1.1(Sep 4, 2017)

  • 3.1.0(Sep 2, 2017)

  • 3.0.3(May 31, 2017)

    • Prevent upload requests from being sent using performMultipart method if they are not of .multipartFormData type and vice versa, add specific assertions and error messages.
    • Added isMultipartRequest property on UploadRequestType.
    Source code(tar.gz)
    Source code(zip)
  • 3.0.2(May 28, 2017)

    • Improved SPM integration and CI scripts
    • Added validationClosure properties on APIRequest, DownloadAPIRequest and UploadAPIRequest that allow customizing validation behaviour. Default behaviour, as before, is calling validate() method on Request.
    Source code(tar.gz)
    Source code(zip)
  • 3.0.1(Feb 22, 2017)

  • 3.0.0(Feb 18, 2017)

    Breaking changes

    • dispatchQueue property was removed from Plugin protocol. All Plugin events are now called synchronously to allow write access to objects, expecially requests. If Plugin requires any specific dispatch queue to run on, it must implement this logic itself.

    Bugfixes

    • APIStub will now print error to console, if it failed to build model from file.
    • NetworkLoggerPlugin will no longer double escape characters, when printing successful request cURL to console.
    Source code(tar.gz)
    Source code(zip)
Owner
MLSDev
MLSDev
Network abstraction layer written in Swift.

Moya 15.0.0 A Chinese version of this document can be found here. You're a smart developer. You probably use Alamofire to abstract away access to URLS

Moya 14.4k Jan 4, 2023
Alamofire Network Layer written in swift 5 using the protocol oriented, combine, UIKit, MVVM.

CoreAPI-iOS This project Contains Alamofire Network layer Based on Protocol Oriented Concept and Combine Framework. It is created with UIKit, Alamofir

Mehran Kamalifard 27 Nov 11, 2022
Dratini is a neat network abstraction layer.

Dratini Dratini is a neat network abstraction layer. If you are looking for a solution to make your network layer neat, Dratini is your choice. Dratin

Kevin Lin 37 Jan 29, 2022
Elegant network abstraction layer in Swift.

Elegant network abstraction layer in Swift. 中文 Design Features Requirements Communication Installation Usage Base Usage - Target - Request - Download

null 100 Dec 9, 2022
NSURLSession network abstraction layer, using Codable and Decodable for response and Encodable for request. ⚙️🚀

SONetworking NSURLSession network abstraction layer, using Codable and Decodable for response and Encodable for request. Project Folder and File Struc

Ahmad AlSofi 4 Jan 28, 2022
Easy and lightweight network layer for creating different set of network requests like GET, POST, PUT, DELETE customizable with coders conforming to TopLevelDecoder, TopLevelEncoder

Easy and lightweight network layer for creating different set of network requests like GET, POST, PUT, DELETE customizable with coders conforming to TopLevelDecoder, TopLevelEncoder

Igor 2 Sep 16, 2022
Alamofire network layer

NVNetworkRequest Alamofire network layer Installation Add this to your Package dependencies: dependencies: [ .package(url: "https://github.com/vin

Vinh Nguyen 0 Nov 19, 2021
Another network wrapper for URLSession. Built to be simple, small and easy to create tests at the network layer of your application.

Another network wrapper for URLSession. Built to be simple, small and easy to create tests at the network layer of your application. Install Carthage

Ronan Rodrigo Nunes 89 Dec 26, 2022
Say goodbye to the Fat ugly singleton Network Manager with this Network Layer

MHNetwork Protocol Oriented Network Layer Aim to avoid having bloated singleton NetworkManager Philosophy the main philosophy behind MHNetwork is to h

Mohamed Emad Hegab 19 Nov 19, 2022
Type-safe networking abstraction layer that associates request type with response type.

APIKit APIKit is a type-safe networking abstraction layer that associates request type with response type. // SearchRepositoriesRequest conforms to Re

Yosuke Ishikawa 1.9k Dec 30, 2022
DBNetworkStack is a network abstraction for fetching request and mapping them to model objects

DBNetworkStack Main Features ?? Typed network resources ?? Value oriented architecture ?? Exchangeable implementations ?? Extendable API ?? Composable

DB Systel GmbH 33 Jan 10, 2022
Advanced Networking Layer Using Alamofire with Unit Testing

Advanced Networking Layer Using Alamofire with Unit Testing

Ali Fayed 8 May 23, 2022
A generic network layer written in swift

SwiftyNet 1.0.0 A generic network layer written in swift. you can use it as an abstraction layer above Alamofire with generic returned types. Installa

Mohamed Salah Zidane 17 Oct 11, 2021
Generic Network Layer created using Swift.

Generic-Network-Layer_iOS Generic Network Layer created using URLSession. Networking is an essential element in app development, and you'll need API c

Shubham Kr. Singh 41 Dec 31, 2022
Async network layer with Combine

Version 1.0.10 Currently Available Platform Version iOS 12.0 tvOS 10.0 macOS 10.15 watchOS 3.0 macCatalyst 13.0 Hover is a Network layer which uses Ap

Onur Hüseyin Çantay 124 Oct 23, 2022
iOS 15, MVVM, Async Await, Core Data, Abstract Network Layer, Repository & DAO design patterns, SwiftUI and Combine

iOS 15, MVVM, Async Await, Core Data, Abstract Network Layer, Repository & DAO design patterns, SwiftUI and Combine

Conrado Mateu Gisbert 18 Dec 23, 2022
VFNetwork is a protocol-oriented network layer that will help you assemble your requests in just a few steps.

Simple, Fast and Easy. Introduction VFNetwork is a protocol-oriented network layer that will help you assemble your requests in just a few steps. How

Victor Freitas 4 Aug 22, 2022
A network extension app to block a user input URI. Meant as a network extension filter proof of concept.

URIBlockNE A network extension app to block a user input URI. Meant as a network extension filter proof of concept. This is just a research effort to

Charles Edge 5 Oct 17, 2022
NWReachability - a pure Swift library for monitoring the network connection of iOS devices using Apple's Network framework.

NWReachability is a pure Swift library for monitoring the network connection of iOS devices using Apple's Network framework.

null 4 Dec 2, 2022