Giter VIP home page Giter VIP logo

requestkit's Introduction

RequestKit

codecov.io

The base of octokit.swift, TanukiKit, TrashCanKit and VloggerKit.

Installation

Carthage

# Cartfile
github "nerdishbynature/RequestKit"

CocoaPods

# Podfile
pod "NBNRequestKit"

Usage

To make a request using RequestKit you will need three parts: a Router, a Configuration and usually an object that know both and connects them. See OctoKit.

Defining a Router

Router are defined by the Router protocol. It is recommended to define them as Enumerations having a case for every route.

This is what a basic router looks like:

enum MyRouter: Router {
    case getMyself(Configuration)

    var configuration: Configuration {
        switch self {
        case .getMyself(let config): return config
        }
    }

    var method: HTTPMethod {
        switch self {
        case .getMyself:
            return .GET
        }
    }

    var encoding: HTTPEncoding {
        switch self {
        case .getMyself:
            return .url
        }
    }

    var path: String {
        switch self {
        case .getMyself:
            return "myself"
        }
    }

    var params: [String: Any] {
        switch self {
        case .getMyself(_):
            return ["key1": "value1", "key2": "value2"]
        }
    }
}

Defining a Configuration

As RequestKit was designed to handle OAuth requests we needed something to store user credentials. This is where Configurations come into play. Configurations are defined in the Configuration protocol.

public struct TokenConfiguration: Configuration {
    public let accessToken: String?
    public let apiEndpoint = "https://my.webservice.example/api/2.0/"
    public let accessTokenFieldName = "access_token"
    public let errorDomain = "com.my.customErrorDomain"
    
    public init(_ accessToken: String? = nil) {
        self.accessToken = accessToken
    }
}

In the above Configuration the accessToken will be passed as a URL parameter named access_token with each request. Alternatively you can have the accessToken passed in an HTTP Authorization header by setting the authorizationHeader property to the desired token type. As an example the following Configuration passes it as a Bearer token.

public struct TokenConfiguration: Configuration {
    public let accessToken: String?
    public let apiEndpoint = "https://my.webservice.example/api/2.0/"
    public let authorizationHeader: String? = "Bearer"
    public let errorDomain = "com.my.customErrorDomain"
        
    public init(_ accessToken: String? = nil) {
        self.accessToken = accessToken
    }
}

Defining the binding object

We will need something that connects the router and the configuration to make provide a convenient interface. The common way of doing this is to use a struct or a class that does it for you.

struct User : Codable {
}

struct MyWebservice {
    var configuration: Configuration

    init(configuration: Configuration) {
        self.configuration = configuration
    }

    func getMyself(session: RequestKitURLSession = URLSession.shared, completion: @escaping (_ response: Response<User>) -> Void) -> URLSessionDataTaskProtocol? {
        let router = MyRouter.getMyself(self.configuration)
        return router.load(session, expectedResultType: User.self) { user, error in
            if let error = error {
                completion(Response.failure(error))
            } else if let user = user {
                completion(Response.success(user))
            }
        }
    }
}

Making a request

All your user has to do is call your MyWebservice:

let config = TokenConfiguration("123456")
MyWebservice(configuration:config).getMyself { response in
    switch response {
        case .success(let user):
            print(user)
        case .failure(let error):
            print(error)
        }
    }
}

requestkit's People

Contributors

pietbrauer avatar mpvosseller avatar tiferrei avatar 417-72ki avatar josephduffy avatar dependabot[bot] avatar niamster avatar nwest avatar lucascodert avatar 1ec5 avatar

Stargazers

Konstantinos Nikoloutsos avatar Sapozhnik Ivan avatar Pavel Kandrashkou avatar  avatar MetaSky avatar Yuan, Jun avatar Arthur Guiot avatar Sami B avatar Maurice Parker avatar __status302 avatar Marc Steven avatar Sergio Rubio avatar BTX avatar Bassem Qoulta avatar alloy avatar William Du avatar Serhii Londar avatar Craze Lattern avatar maicoder avatar Shingo Hiraya avatar Jason Nam avatar  avatar Alex avatar Jens Kohl avatar  avatar Mark Anderson avatar Boris Bügling avatar

Watchers

Alex avatar  avatar James Cloos avatar Marcin Polak avatar  avatar BTX avatar  avatar Takayuki_Sei avatar Muhd Mirza avatar Haris Khaliq avatar Matheus Alano avatar Maurice Parker avatar Franco Meloni avatar

requestkit's Issues

Giving more detail on errors.

Hello there,

I'm working with an API where if a code 400 is returned, it also sends JSON data containing an error property with a short description of the error. I was wondering if there was a way to extend the Error passed to the user to contain not only the HTTP status code but also this error message. Is this possible?

Thank you,
Tiago

Linux Compatability

/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/JSONPostRouter.swift:27:61: error: '[String : AnyObject]?' is not convertible to 'AnyObject?'; did you mean to use 'as!' to force downcast?
                        userInfo[RequestKitErrorKey] = json as AnyObject?
                                                       ~~~~~^~~~~~~~~~~~~
                                                            as!
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/JSONPostRouter.swift:29:56: error: cannot convert value of type 'String' to type 'AnyObject?' in coercion
                        userInfo[RequestKitErrorKey] = string as AnyObject?
                                                       ^~~~~~
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/JSONPostRouter.swift:72:61: error: '[String : AnyObject]?' is not convertible to 'AnyObject?'; did you mean to use 'as!' to force downcast?
                        userInfo[RequestKitErrorKey] = json as AnyObject?
                                                       ~~~~~^~~~~~~~~~~~~
                                                            as!
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/JSONPostRouter.swift:74:56: error: cannot convert value of type 'String' to type 'AnyObject?' in coercion
                        userInfo[RequestKitErrorKey] = string as AnyObject?
                                                       ^~~~~~
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/Router.swift:75:62: error: cannot convert value of type 'String' to type 'AnyObject?' in coercion
            parameters[configuration.accessTokenFieldName] = accessToken as AnyObject?
                                                             ^~~~~~~~~~~
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/Router.swift:167:61: error: '[String : AnyObject]?' is not convertible to 'AnyObject?'; did you mean to use 'as!' to force downcast?
                        userInfo[RequestKitErrorKey] = json as AnyObject?
                                                       ~~~~~^~~~~~~~~~~~~
                                                            as!
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/Router.swift:202:61: error: '[String : AnyObject]?' is not convertible to 'AnyObject?'; did you mean to use 'as!' to force downcast?
                        userInfo[RequestKitErrorKey] = json as AnyObject?
                                                       ~~~~~^~~~~~~~~~~~~
                                                            as!

When trying to compile the code in Linux a cast from [String : AnyObject]? to AnyObject? fails as on macOS, String is convertible to AnyObject due to Foundation’s automatic bridging with NSString, which is a reference type. On Linux, that bridge doesn’t exist. I was wondering if maybe casting to Any? would work, although we still have to make sure the code is Objective-C compatible.

Any suggestions?

Should 2.5.0 be 3.0?

Hey Piet! 👋

I saw the RequestKit 2.5.0 tag appear via an SPM update. It looks like OctoKit fails to build with it, given the Response public type is gone from the interface.

Could maybe make the 2.5.0 a 3.0 instead, which would prevent the upgrade in OctoKit (and other things depending on Response) ?

Thank you! Happy holidays! :-)

Parsing enquiry

Good morning,

I would like to know if there are any alternative ways of parsing JSON responses that include a lot of indented levels.

For example, on OctoKit, indented levels are treated as another class, for example the class User is also used to parse the info on who created a milestone on the Milestone class, is this the only way to do it? What are the alternatives if there is a lot levels?

{
  "_id": "tt3110958",
  "imdb_id": "tt3110958",
  "title": "Now You See Me 2",
  "year": "2016",
  "synopsis": "One year after outwitting the FBI and winning the public’s adulation with their mind-bending spectacles, the Four Horsemen resurface only to find themselves face to face with a new enemy who enlists them to pull off their most dangerous heist yet.",
  "runtime": "129",
  "released": 1465516800,
  "trailer": "http://youtube.com/watch?v=4I8rVcSQbic",
  "certification": "PG-13",
  "torrents": {
    "en": {
      "1080p": {
        "provider": "YTS",
        "filesize": "1.97 GB",
        "size": 2115271393,
        "peer": 7694,
        "seed": 8397,
        "url": "magnet:?xt=urn:btih:EC8D03A62DCB4B0F96F0EEDB05C5CE02A53A3F44&tr=udp://glotorrents.pw:6969/announce&tr=udp://tracker.opentrackr.org:1337/announce&tr=udp://torrent.gresille.org:80/announce&tr=udp://tracker.openbittorrent.com:80&tr=udp://tracker.coppersurfer.tk:6969&tr=udp://tracker.leechers-paradise.org:6969&tr=udp://p4p.arenabg.ch:1337&tr=udp://tracker.internetwarriors.net:1337"
      },
      "720p": {
        "provider": "YTS",
        "filesize": "951 MB",
        "size": 997195776,
        "peer": 11612,
        "seed": 10787,
        "url": "magnet:?xt=urn:btih:D066D4D0EBEFB95102BB44FECDEB5A5FD519E29F&tr=udp://glotorrents.pw:6969/announce&tr=udp://tracker.opentrackr.org:1337/announce&tr=udp://torrent.gresille.org:80/announce&tr=udp://tracker.openbittorrent.com:80&tr=udp://tracker.coppersurfer.tk:6969&tr=udp://tracker.leechers-paradise.org:6969&tr=udp://p4p.arenabg.ch:1337&tr=udp://tracker.internetwarriors.net:1337"
      }
    }
  },
  "genres": [
    "action",
    "comedy",
    "thriller",
    "adventure",
    "crime",
    "mystery"
  ],
  "images": {
    "poster": "https://walter.trakt.us/images/movies/000/188/631/posters/original/7d57d78e40.jpg",
    "fanart": "https://walter.trakt.us/images/movies/000/188/631/fanarts/original/a6cafc7643.jpg",
    "banner": "https://walter.trakt.us/images/movies/000/188/631/banners/original/636d4ffed7.jpg"
  },
  "rating": {
    "percentage": 74,
    "watching": 72,
    "votes": 4612,
    "loved": 100,
    "hated": 100
  }
}

How would I parse the "inner" elements? Would I need to create separate classes for rating, images, etc?

Thank you,
MrAppleMan

Breaking API Changes

Hello @pietbrauer. I think it would have been better to release changes from 2.5.0 as a major version bump as of now it breaks some projects such as https://github.com/nerdishbynature/octokit.swift and https://github.com/danger/swift.

I could not find any issues related to this yet, but I can see that the release is still quite fresh, so I assume this is not only my local issue.

I think the main reason is the deletion of the Response structure here. However, I am not 100% sure this is the only breaking change because I have not investigated it further and as far as I can see there are quite a lot of changes apart from that one.

Nevertheless, I think another part of the story is that these projects use RequestKit as a dependency with package(name:url:from:) and the Apple Documentation states:

Adds a package dependency that uses the version requirement, starting with the given minimum version, going up to the next major version.

Personally, I think it would be better to revert and re-release the RequestKit to save the trouble for other developers changing their Package.swift files to pin the 2.3.0 release or updating their the usage code to the new API which is more time-consuming tbh 🙂

Please let me know if more information is required from my side. I would be glad to help.

Originally posted by @pkondrashkov in #75 (comment)

Parsing variable array attributes

Good morning,
I am trying to come up with a way to represent this with an object:

{
    "timetable":{
        "2018-01-29": [
            {
                "location": {
                    "address": [
                        "29 Gordon Sq",
                        "London",
                        "WC1H 0PP"
                    ],
                    "name": "Gordon House 106",
                    "sitename": "Gordon House",
                    "type": "CB",
                    "capacity": 50
                },
                "end_time": "18:00:00",
                "module": {
                    "module_id": "COMP3058",
                    "lecturer": {
                        "email": "[email protected]",
                        "name": "GORSE, Denise (Dr)"
                    },
                    "name": "Artificial Intelligence and Neural Computing",
                    "course_owner": "COMPS_ENG",
                },
                "duration": 120,
                "start_time": "16:00:00"
            }
        ]
    },
    "ok": true
}

The part that is troubling me is the "2018-01-29" array, which shows the date for an appointment. I'm not seeing how I can set the value of the variable to its JSON if the attribute changes with the data. So for example I can't just do:

date = json["any YYY-MM-DD date in here?"] as ...

Do you know of any way to handle this or is there something in the JSON or REST standards that says that atributtes should be static and predictable? Making an API change might be an option, but only if this turns out to be a violation of the protocols.

Thank you,
Tiago

Swift 3.0 Xcode Beta 6

Good evening,
I believe the swift 3 branch needs to be updated for the beta 6, it comes up with some nasty bugs when I try to use the new beta.

Thank you,
tiferrei

One framework with multiple APIs

Good morning, sorry to bother but I would like to know if it possible to use RequestKit with multiple APIs. I would like to create a single framework that would "speak" to multiple APIs, for example, creating a "Social framework" which is able to handle connections with the Facebook API, Twitter API, etc. But in one, unified framework.

Thank you,
MrAppleMan

Router crashing on TanukiKit Unit Tests

Hello there,

first of all, I apologise if this issue is not 100% caused by RequestKit, I was not completely sure wether to open it here or in TanukiKit, but here made more sense as the crash happens with RequestKit.

When running a simple unit test to get the commits from a project, I am presented with a crash on this line:

#0	0x00000001112348c5 in Router.request() -> URLRequest? at /Users/tiferrei/Developer/TanukiKit/Carthage/Checkouts/RequestKit/RequestKit/Router.swift:53
RequestKit was compiled with optimization - stepping may behave oddly; variables may not be available.

As you can see, the logs don't really say anything specific, what I know is that the project compiles successfully, but crashes on the test, furthermore, all other tests pass, only this one crashes.
If it helps, I pushed a commit to Travis to get some logs.

If there's any further debugging I can do from my side, please request it, I only provided this information because I didn't how to further debug it.

Tiago

Swift3 Adaptations

Small problem on the String+Additions file for swift3:

let characterSet = CharacterSet.urlQueryAllowed.mutableCopy() as! NSMutableCharacterSet –> Value of type 'CharacterSet' has no member 'mutableCopy'.

Can be related to this:
SE-0069

Returning data in dictionary format

Recently I've been trying to come up with a way to let users access not only the pretty object parsed data, but also more raw data like the the returned JSON in dictionary format. I was hoping to be able to do something like this:

public func rooms(_ session: RequestKitURLSession = URLSession.shared, roomID: String = "", roomName: String = "", siteID: String = "", siteName: String = "", classification: Classification = Classification.Unknown, capacity: String = "", _ inDictionary: Bool = false, completion: @escaping (_ response: Response<Any>) -> Void) -> URLSessionDataTaskProtocol? {
        let router = RoomBookingsRouter.readRooms(configuration, roomID, roomName, siteID, siteName, classification, capacity)
        if inDictionary {
            return router.load(session, expectedResultType: [String: Any].self) {
            // ...
        }
        return router.load(session, expectedResultType: RoomsResponse.self) { rooms, error in
           // ...
        }
    }

However, due to having the completion defined in the function header, I need to specify a return type.

Any ideas on how to better approach this?

Thanks a lot,
Tiago

Allow non-string JSON parameter values

Router expects all the parameter values to be Strings, but if the payload for a request can be JSON-encoded, it should be possible for a parameter value to be another JSON-representable type, such as a number or array of strings. Specifically, I was unable to implement support for setting labels or milestones on issues in nerdishbynature/octokit.swift#36 because the API expects an array of strings for labels and a numeric ID for the milestone.

Allow API user to specify the type in RequestKitErrorResponseKey

@pietbrauer @tiferrei

Related to #38 and #39

Right now if a request is not successful the returned JSON is parsed as a generic [String: AnyObject] and placed into userInfo[RequestKitErrorResponseKey]. How would you feel about allowing the developer to specify the specific type to parse that JSON as?

By way of example, a developer might define a structure like this:

struct MyErrorResponse : Codable {
    var message : String?
    var field : String?
    var code : Int?
}

And then they could pass expectedErrorResponseType:MyErrorResponse.self to load like this:

    func getJSON(_ session: RequestKitURLSession = URLSession.shared, completion: @escaping (_ response: Response<[String: AnyObject]>) -> Void) -> URLSessionDataTaskProtocol? {
        let router = JSONTestRouter.testGET(configuration)
        return router.load(session, expectedResultType: [String: AnyObject].self, expectedErrorResponseType:MyErrorResponse.self) { json, error in
            if let error = error {
                completion(Response.failure(error))
            } else {
                if let json = json {
                    completion(Response.success(json))
                }
            }
        }
    }

If a request was not successful and expectedErrorResponseType was provided then RequestKit would parse the JSON with that specific type.

The user could then more easily access the value out of userInfo[RequestKitErrorResponseKey] like this:

        let task = TestInterface().getJSON(session) { response in
            switch response {
            case .success:
                print("success")
            case .failure(let error as NSError):
                let myError = error.userInfo[RequestKitErrorKey] as? MyErrorResponse
                print(myError.message)
                print(myError.field)
                print(myError.code)
            }
        }

We might even consider just passing the MyErrorResponse object as the error itself but I haven't thought that all through.

WDYT?

Xcode 8.1 requires Swift version 3.0.1

Good evening,

I keep getting an error whilst developing for TanukiKit, as Xcode requires me to update dependent frameworks to Swift 3.0.1, the error is as follows:

Module compiled with Swift 3.0 cannot be imported in Swift 3.0.1

Thank you,
tiferrei

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.