Overhauled the library with several new features (#5)

## Summary

Updates the library to v4.5.1 of the App Store Connect API, and ships it as a breaking 2.0.0 release with pagination, API key authentication, rate limiting, and a lighter install for consumers.

## Breaking changes

- **Minimum platforms:** iOS 14, macOS 11, tvOS 14, watchOS 7, and visionOS 1.
- **Toolchain:** Swift 6.0+ (Xcode 16+). The package builds in the Swift 6 language mode.
- **Runtime:** requires `swift-openapi-runtime` 1.11.0 or later.

## Changes

- **API:** updated the OpenAPI specification to v4.5.1, covering 1,303 operations and 1,473 schemas.
- **Pagination:** the spec patch adds the undocumented `cursor` query parameter to the 465 paged operations. `PagedDocumentLinks.nextCursor` reads the cursor from a page, and `PagedSequence` iterates every page.
- **Authentication:** `APIKeyTokenProvider` signs ES256 tokens from an API key and reuses each one until a minute before it expires. `BearerAuthMiddleware` now accepts a token provider.
- **Rate limiting:** `RateLimitMiddleware` retries `429` responses, waiting for `Retry-After` or backing off exponentially.
- **Generated code:** committed to `Sources/ASConnectService/Sources/Public/Generated` instead of generated by a build plugin. Consumers now resolve 4 packages instead of 12, and Xcode no longer asks to trust a plugin.
- **Tooling:**
  - `make oas-download` now downloads, patches, generates, and checks the docs in one go.
  - New `make oas-generate`, `make oas-validate`, and `make doc-check` targets.
  - The generator is pinned in `Tools/`, and the DocC plugin is only resolved by the documentation targets.
- **Documentation:** the DocC catalog now lists every operation and schema in the spec, and the catalog and README are rewritten for the new APIs.
- **Housekeeping:** Apache 2.0 license headers on every Swift file, including `Package.swift` and the tests.

Reviewed-on: #5
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
This commit was merged in pull request #5.
This commit is contained in:
javier authored and Javier Cicchelli committed 2026-10-25 17:52:37 +00:00
1 parent 3aaf5cd7a5
commit 0431fb5133
27 files changed
+1046471 -284

No files matched your search

+81 -23
View File
@@ -4,9 +4,7 @@ A Swift client library for the App Store Connect API, generated from the officia
## Overview
`ASConnectService` provides a type-safe, Swift-native interface to Apple's App Store Connect API. This package enables developers to programmatically interact with App Store Connect services for managing apps, builds, reviews, sales reports, and more.
The library is automatically generated from the official App Store Connect API OpenAPI specification using Apple's [swift-openapi-generator](https://github.com/apple/swift-openapi-generator), ensuring complete API coverage and type safety.
`ASConnectService` exposes every endpoint of Apple's App Store Connect API as a Swift method with typed requests and responses. It's generated from the official OpenAPI specification with [Swift OpenAPI Generator](https://github.com/apple/swift-openapi-generator).
## Installation
@@ -14,7 +12,7 @@ Add `ASConnectService` as a dependency in your `Package.swift` file:
```swift
dependencies: [
.package(url: "https://github.com/rock-n-code/asconnect-service.git", from: "1.0.0")
.package(url: "https://github.com/rock-n-code/asconnect-service.git", from: "2.0.0")
]
```
@@ -33,42 +31,81 @@ Then add it to your target dependencies:
### Creating a Client
Create a `Client` instance by providing a server URL and transport. Use `BearerAuthMiddleware` to authenticate requests with a JSON Web Token (JWT).
The App Store Connect API requires authentication using API keys. You'll need to:
1. Create an API key in App Store Connect
2. Generate a signed JWT token using your key ID, issuer ID, and private key
3. Pass the token to the built-in `BearerAuthMiddleware` when creating the client
Create a `Client` with a server URL, a transport, and a `BearerAuthMiddleware`. With an API key from App Store Connect, `APIKeyTokenProvider` signs the JSON Web Tokens (JWT) the API requires, and renews them before they expire:
```swift
import ASConnectService
import OpenAPIURLSession
let tokenProvider = try APIKeyTokenProvider(
issuerID: yourIssuerID,
keyID: yourKeyID,
privateKey: yourP8FileContents
)
let client = Client(
serverURL: try Servers.server1(),
serverURL: try Servers.Server1.url(),
transport: URLSessionTransport(),
middlewares: [
BearerAuthMiddleware(token: yourJWTToken)
BearerAuthMiddleware { try await tokenProvider.token() }
]
)
```
### Making API Calls
The `Client` conforms to `APIProtocol`, which defines a method for every endpoint in the App Store Connect API. Each method accepts an `Input` value and returns an `Output` value with the response.
To use a token you signed yourself, pass it directly. It expires after 20 minutes at most:
```swift
let response = try await client.appsGetCollection(.init())
BearerAuthMiddleware(token: yourJWTToken)
```
## Supported Platforms
### Making API Calls
- iOS 13.0+
- macOS 10.15+
- tvOS 13.0+
Each endpoint is a method on `Client`, declared by `APIProtocol`. It returns an `Output` enum with a case for each documented response:
```swift
let response = try await client.appsGetCollection(query: .init(limit: 10))
let apps = try response.ok.body.json.data
```
The `ok` property throws for any other response. To handle those, switch over the `Output` cases, such as `.unauthorized` or `.undocumented(statusCode:_:)`.
### Fetching More Pages
Lists are paged. Iterate a `PagedSequence` to fetch each page in turn:
```swift
let pages = PagedSequence(links: \.links) { cursor in
try await client.appsGetCollection(query: .init(limit: 200, cursor: cursor)).ok.body.json
}
var apps: [Components.Schemas.App] = []
for try await page in pages {
apps += page.data
}
```
To fetch pages yourself, pass a page's `links.nextCursor` as the `cursor` of the next request.
### Handling Rate Limits
Add `RateLimitMiddleware` before the authentication middleware to retry `429 Too Many Requests` responses:
```swift
middlewares: [
RateLimitMiddleware(),
BearerAuthMiddleware { try await tokenProvider.token() }
]
```
## Requirements
- Swift 6.0+ (Xcode 16+)
- iOS 14.0+
- macOS 11.0+
- tvOS 14.0+
- visionOS 1.0+
- watchOS 6.0+
- watchOS 7.0+
## Development
@@ -95,13 +132,34 @@ make doc-generate-github
# Preview documentation locally in Safari
make doc-preview
# Check the catalog covers the generated code
make doc-check
```
### Updating the API
The generated code is committed in `Sources/ASConnectService/Sources/Public/Generated`, so consumers don't run the generator.
```bash
# Update to the latest specification
make oas-download
# Regenerate the code only
make oas-generate
# Validate the specification only
make oas-validate
```
## Dependencies
- [swift-openapi-generator](https://github.com/apple/swift-openapi-generator)
- [swift-openapi-runtime](https://github.com/apple/swift-openapi-runtime)
- [swift-openapi-urlsession](https://github.com/apple/swift-openapi-urlsession)
Development only:
- [swift-openapi-generator](https://github.com/apple/swift-openapi-generator), in `Tools`
- [swift-docc-plugin](https://github.com/swiftlang/swift-docc-plugin)
## License