Giter VIP home page Giter VIP logo

decree's People

Contributors

drewag avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

decree's Issues

Setting custom headers for certain endpoints only

I already explained the context of my API elsewhere but I'll do a gist here for completion sake.

I have 3 endpoints named login, verify and profile. I don't need to pass any additional custom headers for the first two. For the third one (then all subsequent requests from there on out), I have to set a custom header. So I've set the authorizationRequirement property like this for all 3.

struct Login: InOutEndpoint {
    typealias Service = MyAPI
    static let authorizationRequirement = AuthorizationRequirement.none
    
    // ...
}

struct Verify: InOutEndpoint {
    typealias Service = MyAPI
    static let authorizationRequirement = AuthorizationRequirement.none
    
    let path: String = "/login/DRI/verify/"
    
    // ..
}

struct GetProfile: OutEndpoint {
    typealias Service = MyAPI
    static let authorizationRequirement = AuthorizationRequirement.required
}

In the WebService implementation, I've set the authorization property like this.

struct MyAPI: WebService {
    static var shared = MyAPI()
    
    let baseURL = URL(string: "http://example.com/api")!
    var authorization = Authorization.custom(key: "token", value: SessionManager.shared.token)
    
    // ..
}

SessionManager is a class where I store the token.

I ran into a bit of a snag when I set the custom header. Let me elaborate. After calling Login() endpoint, I call Verify(). This is where I get the value for the custom header. I save the token value in the SessionManager.

Verify().makeRequest(with: .init(phoneno: phoneNumber, code: otp)) { result in
    switch result {
    case .success(let output):
        SessionManager.shared.token = output.data.token
    case .failure(let error):
        print("Failed to verify: \(error)")
    }
}

I then call Profile() endpoint and noticed that the request fails for not having a value for the custom header. I assume that MyAPI (WebService implementation) is only initialized once so the newly assigned value to SessionManager.shared.token above isn't getting applied to the custom header when I call the next request.

So I assigned the token to the custom header directly like so.

Verify().makeRequest(with: .init(phoneno: phoneNumber, code: otp)) { result in
    switch result {
    case .success(let output):
        MyAPI.shared.authorization = Authorization.custom(key: "token", value: output.data.token)
    case .failure(let error):
        print("Failed to verify: \(error)")
    }
}

This fixes the issue. However it just looks....off. Because I'm already setting var authorization = Authorization.custom(key: "token", value: SessionManager.shared.token) in the web service implementation with no effect so I have to set it from "outside".

Is this the correct way of doing this? I remember you mentioning about considering a way to add headers directly to the endpoints themselves. Which I also think is a better approach since you have more control over it. Did you decide against it or is it still on the table?

Deprecate callback APIs in favor of Swift 5.5 concurrency

Swift 5.5โ€™s new concurrency system is designed to be a drop-in replacement for callback APIs, and improves upon them considerably. As such, you should consider adopting it as soon as possible.

One of the benefits of the new concurrency system is the ability to overload a method with synchronous and asynchronous implementations. This means you can use the same name for both, which is considered best practice going forward.

Custom Headers for Endpoints

The ideas was initially discussed here.

Even outside of auth, certain endpoints may want to include custom headers.

The big question is whether to think of those headers as additional input or something else? Should they simply be an optional endpoint property of type [(String,String?)] or should we somehow use Coding? Should headers be one of the input formats? What if we want a combination of headers, url query, and body content?

Implementing a custom ErrorResponse

From the API I'm working with, I get error messages in a format like this.

{
  "status": "fail",
  "code": 400,
  "data": null,
  "message": [
    "phoneno: Enter a valid phone no. This value should be 11 digits folowed by + sign."
  ]
}

I want to display the strings that come inside the message array to the user when an error occurs. So I intended to implement my own ErrorResponse.

The problem is it already has a variable called message. And it is of type String. I can't turn it into a [String] because message is a required property.

So I put together a workaround like this.

struct APIErrorResponse: AnyErrorResponse, Decodable {
    let message: String
    let messages: [String]?
    
    enum CodingKeys: String, CodingKey {
        case message = "m"
        case messages = "message"
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        message = ""
        messages = try container.decodeIfPresent([String].self, forKey: .messages)
        print(messages)
    }
}

However I'm not getting this response in the .fail case where I call the endpoint. I put a breakpoint inside the nit(from decoder: Decoder) and the JSON is parsed and the property is assigned the value too but it's not coming to topside. I traced the execution back to the func parse<Output: Decodable, E: Endpoint>(from data: Data?, for endpoint: E) throws -> Output method but I'm unable to figure out what goes wrong from there.

File Streaming

Right now, all inputs and outputs must be loaded into memory in their entirety. It should be possible to stream the contents of a file as input and stream the output to disk to be more memory efficient.

This will involve enhancing the File type to include a disk option and then special casing those in WebService+MakeRequest.

Separate containers for third-party services

A small suggestion. Maybe you could consider extracting the third-party services out to separate containers? To keep the main library from bloating. Like Eureka did with their custom rows catalog.

Because currently, if you were to add the source files manually, you get compile errors in those third-party files. So users who don't need them have to remove those files and bits and pieces of code from here and there to get it working.

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.