AvdLee / appstoreconnect-swift-sdk

The Swift SDK to work with the App Store Connect API from Apple.
Other
1.48k stars 198 forks source link

Adds rate limit to APIProvider #227

Closed mathiasemil closed 1 year ago

mathiasemil commented 1 year ago

APIProvider now exposes rate limit information from the X-Rate-Limit header field.

public let rateLimitPublisher = PassthroughSubject<RateLimit, Never>()

Rate limits are included in the header for every response and are enforced for all requests using the same API Key.

The documentation defines that the header info includes:

However certain endpoints will also include user-minute-lim and user-minute-rem. I have filed a feedback to ask that this is added to the documentation. Since this solution does not make assumptions about which entries are included in X-Rate-Limit this should not be an issue.

Usage

let cancellable = apiProvider.rateLimitPublisher.sink { rateLimit in
    if let remaining = rateLimit.entries["user-hour-rem"], let limit = rateLimit.entries["user-hour-lim"] {
        print("Rate limit: \(remaining)/\(limit)")
    }
}

Per endpoint limits Rate limits apply to all requests, but it appears it is possible for certain endpoints have their own limits. Because of this I have added requestURL to RateLimit so you're able to see rate limits for specific endpoints.

SwiftLeeBot commented 1 year ago
Warnings
:warning: 'Prices' is deprecated: Deprecated
:warning: 'AvailableTerritories' is deprecated: Deprecated
:warning: 'InAppPurchases' is deprecated: Deprecated
:warning: 'Prices' is deprecated: Deprecated
:warning: 'AvailableTerritories' is deprecated: Deprecated
:warning: 'InAppPurchases' is deprecated: Deprecated
:warning: 'AppPrice' is deprecated: Deprecated
:warning: 'AgeRatingDeclaration' is deprecated: Deprecated
:warning: 'AgeRatingDeclaration' is deprecated: Deprecated
:warning: 'AppStoreVersionSubmission' is deprecated: Deprecated
:warning: 'AppStoreVersionSubmission' is deprecated: Deprecated
:warning: 'Prices' is deprecated: Deprecated
:warning: 'AvailableTerritories' is deprecated: Deprecated
:warning: 'Prices' is deprecated: Deprecated
:warning: 'AvailableTerritories' is deprecated: Deprecated
:warning: 'AppPrice' is deprecated: Deprecated
:warning: 'Prices' is deprecated: Deprecated
:warning: 'AvailableTerritories' is deprecated: Deprecated
:warning: 'InAppPurchases' is deprecated: Deprecated
:warning: 'AppPrice' is deprecated: Deprecated
:warning: 'AgeRatingDeclaration' is deprecated: Deprecated
:warning: 'AppStoreVersionSubmission' is deprecated: Deprecated
:warning: 'AppStoreVersionSubmission' is deprecated: Deprecated
:warning: 'Prices' is deprecated: Deprecated
:warning: 'AvailableTerritories' is deprecated: Deprecated
:warning: 'AppPrice' is deprecated: Deprecated
Messages
:book: AppStoreConnect-Swift-SDK-Tests: Executed 16 tests (0 failed, 0 retried, 0 skipped) in 0.067 seconds
:book: View more details on Bitrise

Code Coverage Report

Name Coverage

SwiftLint found issues

Severity File Reason
Warning RateLimit.swift:13 Lines should not have trailing whitespace. (trailing_whitespace)
Warning RateLimit.swift:16 Lines should not have trailing whitespace. (trailing_whitespace)
Warning RateLimit.swift:19 Lines should not have trailing whitespace. (trailing_whitespace)
Error RateLimitTests.swift:41 Line should be 160 characters or less: currently 215 characters (line_length)
Warning RateLimitTests.swift:9 Imports should be sorted. (sorted_imports)
Warning RateLimitTests.swift:19 Lines should not have trailing whitespace. (trailing_whitespace)
Warning RateLimitTests.swift:24 Lines should not have trailing whitespace. (trailing_whitespace)
Warning RateLimitTests.swift:30 Lines should not have trailing whitespace. (trailing_whitespace)
Warning RateLimitTests.swift:39 Lines should not have trailing whitespace. (trailing_whitespace)
Warning DefaultRequestExecutor.swift:67 Line should be 140 characters or less: currently 153 characters (line_length)
Warning DefaultRequestExecutor.swift:86 Line should be 140 characters or less: currently 156 characters (line_length)
Warning DefaultRequestExecutor.swift:35 Chained function calls should be either on the same line, or one per line. (multiline_function_chains)
Warning DefaultRequestExecutor.swift:46 Chained function calls should be either on the same line, or one per line. (multiline_function_chains)
Warning DefaultRequestExecutor.swift:60 Use shorthand syntax for optional binding (shorthand_optional_binding)
Warning DefaultRequestExecutor.swift:79 Use shorthand syntax for optional binding (shorthand_optional_binding)
Warning APIProvider.swift:73 Use shorthand syntax for optional binding (shorthand_optional_binding)
Warning APIProvider.swift:9 Imports should be sorted. (sorted_imports)
Warning APIProvider.swift:135 Lines should not have trailing whitespace. (trailing_whitespace)
Warning APIProvider.swift:241 Lines should not have trailing whitespace. (trailing_whitespace)
Warning APIProvider.swift:271 Lines should not have trailing whitespace. (trailing_whitespace)
Warning APIProvider.swift:292 Lines should not have trailing whitespace. (trailing_whitespace)
Warning APIProvider.swift:309 Lines should not have trailing whitespace. (trailing_whitespace)
Warning APIProvider.swift:319 Lines should not have trailing whitespace. (trailing_whitespace)
Warning APIProvider.swift:335 Lines should not have trailing whitespace. (trailing_whitespace)
Warning APIProvider.swift:348 Lines should not have trailing whitespace. (trailing_whitespace)
Warning APIProvider.swift:359 Lines should not have trailing whitespace. (trailing_whitespace)
Warning APIProvider.swift:369 Lines should not have trailing whitespace. (trailing_whitespace)
Warning APIProvider.swift:377 Lines should not have trailing whitespace. (trailing_whitespace)
Warning APIProvider.swift:103 Parentheses are not needed when declaring closure arguments. (unneeded_parentheses_in_closure_argument)
Warning APIProviderTests.swift:43 Method 'setUp()' should call to super function (overridden_super_call)
Warning APIProviderTests.swift:9 Imports should be sorted. (sorted_imports)

Generated by :no_entry_sign: Danger Swift against ae3af9799778047099bc3f2d1d0825ce63bcd2ce

mathiasemil commented 1 year ago

It turns out there was a case sensitivity issue when looking up the rate limit header field name. Apparently Proxyman uppercases all header field names and since the API returns lowercased field names the solution only worked when Proxyman was running🤦‍♂️

I changed the solution to use value(forHTTPHeaderField:) which ensures header field names are case-insensitive.