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
+1046470 -283

No files matched your search

+4
View File
@@ -15,6 +15,7 @@
# --- DOCUMENTATION --- # --- DOCUMENTATION ---
DOCC_ARCHIVE_OUTPUT=./${SPM_LIBRARY_TARGET}.doccarchive DOCC_ARCHIVE_OUTPUT=./${SPM_LIBRARY_TARGET}.doccarchive
DOCC_CATALOG=Sources/$(SPM_LIBRARY_TARGET)/Catalogs/$(SPM_LIBRARY_TARGET).docc
DOCC_GITHUB_OUTPUT=./docs DOCC_GITHUB_OUTPUT=./docs
DOCC_GITHUB_BASE_PATH=asconnect-service DOCC_GITHUB_BASE_PATH=asconnect-service
DOCC_PREVIEW_URL=http://localhost:8080/documentation/asconnectservice DOCC_PREVIEW_URL=http://localhost:8080/documentation/asconnectservice
@@ -26,6 +27,9 @@ OAS_DOWNLOAD_FILE=$(OAS_DOWNLOAD_FOLDER)/openapi.oas.json
OAS_DOWNLOAD_INPUT=$(OAS_DOWNLOAD_FOLDER)/asconnect-openapi-specification.zip OAS_DOWNLOAD_INPUT=$(OAS_DOWNLOAD_FOLDER)/asconnect-openapi-specification.zip
OAS_DOWNLOAD_OUTPUT=Sources/$(SPM_LIBRARY_TARGET)/openapi.json OAS_DOWNLOAD_OUTPUT=Sources/$(SPM_LIBRARY_TARGET)/openapi.json
OAS_DOWNLOAD_URL=https://developer.apple.com/sample-code/app-store-connect/app-store-connect-openapi-specification.zip OAS_DOWNLOAD_URL=https://developer.apple.com/sample-code/app-store-connect/app-store-connect-openapi-specification.zip
OAS_GENERATE_CONFIG=Sources/$(SPM_LIBRARY_TARGET)/openapi-generator-config.yaml
OAS_GENERATE_OUTPUT=Sources/$(SPM_LIBRARY_TARGET)/Sources/Public/Generated
OAS_GENERATE_TOOLS=./Tools
# -- SWIFT PACKAGE MANAGER --- # -- SWIFT PACKAGE MANAGER ---
+40 -3
View File
@@ -19,6 +19,11 @@ environment ?= .env
include $(environment) include $(environment)
export $(shell sed 's/=.*//' $(environment)) export $(shell sed 's/=.*//' $(environment))
# Uses the DocC executable from Xcode's default toolchain, as some Swift toolchains (e.g. 6.4.0) ship an x86_64-only one.
DOCC_EXEC ?= $(shell xcrun --toolchain com.apple.dt.toolchain.XcodeDefault --find docc 2>/dev/null)
export DOCC_EXEC
# LIBRARY # LIBRARY
lib-build: ## Builds the library lib-build: ## Builds the library
@@ -57,7 +62,7 @@ pkg-update: ## Updates the SPM package dependencies
doc-generate: doc-generate-archive doc-generate-github ## Generates the library documentation for both Github and Xcode doc-generate: doc-generate-archive doc-generate-github ## Generates the library documentation for both Github and Xcode
doc-generate-archive: ## Generates the library documentation archive for Xcode doc-generate-archive: ## Generates the library documentation archive for Xcode
@swift package \ @ENABLE_DOCC_PLUGIN=1 swift package \
--allow-writing-to-directory $(DOCC_ARCHIVE_OUTPUT) \ --allow-writing-to-directory $(DOCC_ARCHIVE_OUTPUT) \
generate-documentation \ generate-documentation \
--target $(SPM_LIBRARY_TARGET) \ --target $(SPM_LIBRARY_TARGET) \
@@ -66,7 +71,7 @@ doc-generate-archive: ## Generates the library documentation archive for Xcode
--output-path $(DOCC_ARCHIVE_OUTPUT) --output-path $(DOCC_ARCHIVE_OUTPUT)
doc-generate-github: ## Generates the library documentation for Github doc-generate-github: ## Generates the library documentation for Github
@swift package \ @ENABLE_DOCC_PLUGIN=1 swift package \
--allow-writing-to-directory $(DOCC_GITHUB_OUTPUT) \ --allow-writing-to-directory $(DOCC_GITHUB_OUTPUT) \
generate-documentation \ generate-documentation \
--target $(SPM_LIBRARY_TARGET) \ --target $(SPM_LIBRARY_TARGET) \
@@ -77,9 +82,12 @@ doc-generate-github: ## Generates the library documentation for Github
--hosting-base-path $(DOCC_GITHUB_BASE_PATH) \ --hosting-base-path $(DOCC_GITHUB_BASE_PATH) \
--output-path $(DOCC_GITHUB_OUTPUT) --output-path $(DOCC_GITHUB_OUTPUT)
doc-check: ## Checks the DocC catalog covers every generated operation and schema
@python3 -I Scripts/check-docc.py "$(OAS_GENERATE_OUTPUT)" "$(DOCC_CATALOG)"
doc-preview: ## Previews the library documentation in Safari doc-preview: ## Previews the library documentation in Safari
@open -a safari $(DOCC_PREVIEW_URL) @open -a safari $(DOCC_PREVIEW_URL)
@swift package \ @ENABLE_DOCC_PLUGIN=1 swift package \
--disable-sandbox \ --disable-sandbox \
preview-documentation \ preview-documentation \
--target $(SPM_LIBRARY_TARGET) \ --target $(SPM_LIBRARY_TARGET) \
@@ -96,6 +104,35 @@ oas-download: ## Downloads the latest App Store Connect OpenAPI specification do
@unzip -q "$(OAS_DOWNLOAD_INPUT)" -d "$(OAS_DOWNLOAD_FOLDER)" @unzip -q "$(OAS_DOWNLOAD_INPUT)" -d "$(OAS_DOWNLOAD_FOLDER)"
@mv "$(OAS_DOWNLOAD_FILE)" "$(OAS_DOWNLOAD_OUTPUT)" @mv "$(OAS_DOWNLOAD_FILE)" "$(OAS_DOWNLOAD_OUTPUT)"
@rm -rf "$(OAS_DOWNLOAD_FOLDER)" @rm -rf "$(OAS_DOWNLOAD_FOLDER)"
@# Generating the code also validates the document.
@$(MAKE) --no-print-directory oas-patch-document
@$(MAKE) --no-print-directory oas-generate
@$(MAKE) --no-print-directory doc-check
oas-patch: oas-patch-document oas-validate # Patches and validates the OpenAPI specification document
oas-patch-document: # Patches the OpenAPI specification document with Scripts/patch-oas.jq
@jq --from-file Scripts/patch-oas.jq "$(OAS_DOWNLOAD_OUTPUT)" > "$(OAS_DOWNLOAD_OUTPUT).tmp"
@mv "$(OAS_DOWNLOAD_OUTPUT).tmp" "$(OAS_DOWNLOAD_OUTPUT)"
oas-validate: ## Validates the OpenAPI specification document
@swift run \
--configuration release \
--package-path "$(OAS_GENERATE_TOOLS)" \
swift-openapi-generator generate \
--config "$(OAS_GENERATE_CONFIG)" \
--dry-run \
"$(OAS_DOWNLOAD_OUTPUT)"
oas-generate: ## Generates the library source code from the OpenAPI specification document
@mkdir -p "$(OAS_GENERATE_OUTPUT)"
@swift run \
--configuration release \
--package-path "$(OAS_GENERATE_TOOLS)" \
swift-openapi-generator generate \
--config "$(OAS_GENERATE_CONFIG)" \
--output-directory "$(OAS_GENERATE_OUTPUT)" \
"$(OAS_DOWNLOAD_OUTPUT)"
# IDE # IDE
+24 -14
View File
@@ -1,27 +1,30 @@
// swift-tools-version: 5.10 // swift-tools-version: 6.0
//===----------------------------------------------------------------------=== // ===----------------------------------------------------------------------===
// //
// This source file is part of the ASConnectService open source project // This source file is part of the ASConnectService open source project
// //
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors // Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under the EUPL 1.2 or later. // Licensed under Apache license v2.0
// //
// See LICENSE for license information // See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors // See CONTRIBUTORS for the list of ASConnectService project authors
// //
//===----------------------------------------------------------------------=== // SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
import class Foundation.ProcessInfo
import PackageDescription import PackageDescription
let package = Package( let package = Package(
name: AppStoreConnectService.package, name: AppStoreConnectService.package,
platforms: [ platforms: [
.iOS(.v13), .iOS(.v14),
.macOS(.v10_15), .macOS(.v11),
.tvOS(.v13), .tvOS(.v14),
.visionOS(.v1), .visionOS(.v1),
.watchOS(.v6) .watchOS(.v7)
], ],
products: [ products: [
.library( .library(
@@ -30,10 +33,9 @@ let package = Package(
), ),
], ],
dependencies: [ dependencies: [
.package(url: "https://github.com/apple/swift-openapi-generator.git", exact: "1.11.0"), // Must be at least the runtime version required by the generator in `Tools`.
.package(url: "https://github.com/apple/swift-openapi-runtime", from: "1.5.0"), .package(url: "https://github.com/apple/swift-openapi-runtime", from: "1.11.0"),
.package(url: "https://github.com/apple/swift-openapi-urlsession", from: "1.0.2"), .package(url: "https://github.com/apple/swift-openapi-urlsession", from: "1.0.2")
.package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.1.0")
], ],
targets: [ targets: [
.target( .target(
@@ -43,8 +45,9 @@ let package = Package(
.product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession") .product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession")
], ],
path: "Sources/ASConnectService", path: "Sources/ASConnectService",
plugins: [ exclude: [
.plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator") "openapi.json",
"openapi-generator-config.yaml"
] ]
), ),
.testTarget( .testTarget(
@@ -57,6 +60,13 @@ let package = Package(
] ]
) )
// Only added by the documentation targets, so consumers don't resolve it.
if ProcessInfo.processInfo.environment["ENABLE_DOCC_PLUGIN"] != nil {
package.dependencies.append(
.package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.1.0")
)
}
// MARK: - Constants // MARK: - Constants
enum AppStoreConnectService { enum AppStoreConnectService {
+81 -23
View File
@@ -4,9 +4,7 @@ A Swift client library for the App Store Connect API, generated from the officia
## Overview ## 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. `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).
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.
## Installation ## Installation
@@ -14,7 +12,7 @@ Add `ASConnectService` as a dependency in your `Package.swift` file:
```swift ```swift
dependencies: [ 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 ### 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). 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:
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
```swift ```swift
import ASConnectService import ASConnectService
import OpenAPIURLSession import OpenAPIURLSession
let tokenProvider = try APIKeyTokenProvider(
issuerID: yourIssuerID,
keyID: yourKeyID,
privateKey: yourP8FileContents
)
let client = Client( let client = Client(
serverURL: try Servers.server1(), serverURL: try Servers.Server1.url(),
transport: URLSessionTransport(), transport: URLSessionTransport(),
middlewares: [ middlewares: [
BearerAuthMiddleware(token: yourJWTToken) BearerAuthMiddleware { try await tokenProvider.token() }
] ]
) )
``` ```
### Making API Calls To use a token you signed yourself, pass it directly. It expires after 20 minutes at most:
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.
```swift ```swift
let response = try await client.appsGetCollection(.init()) BearerAuthMiddleware(token: yourJWTToken)
``` ```
## Supported Platforms ### Making API Calls
- iOS 13.0+ Each endpoint is a method on `Client`, declared by `APIProtocol`. It returns an `Output` enum with a case for each documented response:
- macOS 10.15+
- tvOS 13.0+ ```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+ - visionOS 1.0+
- watchOS 6.0+ - watchOS 7.0+
## Development ## Development
@@ -95,13 +132,34 @@ make doc-generate-github
# Preview documentation locally in Safari # Preview documentation locally in Safari
make doc-preview 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 ## Dependencies
- [swift-openapi-generator](https://github.com/apple/swift-openapi-generator)
- [swift-openapi-runtime](https://github.com/apple/swift-openapi-runtime) - [swift-openapi-runtime](https://github.com/apple/swift-openapi-runtime)
- [swift-openapi-urlsession](https://github.com/apple/swift-openapi-urlsession) - [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) - [swift-docc-plugin](https://github.com/swiftlang/swift-docc-plugin)
## License ## License
+83
View File
@@ -0,0 +1,83 @@
# ===------------------------------------------------------------------------------------===
#
# This source file is part of the App Store Connect Service open source project
#
# Copyright (c) 2026 Röck+Cöde VoF. and the App Store Connect Service project authors
# Licensed under Apache license v2.0
#
# See LICENSE for license information
# See CONTRIBUTORS for the list of App Store Connect Service project authors
#
# SPDX-License-Identifier: Apache-2.0
#
# ===------------------------------------------------------------------------------------===
"""Checks that the DocC catalog lists every generated operation and schema, and nothing else.
Usage: python3 check-docc.py <generated sources folder> <DocC catalog folder>
"""
import re
import sys
def generated_symbols(types_path):
"""Returns the methods, operations, and schemas in the generated `Types.swift` file."""
lines = open(types_path).read().split('\n')
def start(prefix):
return next(index for index, line in enumerate(lines) if line.startswith(prefix))
protocol = lines[start('public protocol APIProtocol'):start('extension APIProtocol {')]
components = lines[start('public enum Components {'):start('public enum Operations {')]
operations = lines[start('public enum Operations {'):]
schema = re.compile(r' (?:@\w+ )*public (?:indirect )?(?:struct|enum|typealias) (\w+)')
return {
'APIProtocol.md': {m.group(1) for line in protocol if (m := re.match(r' func (\w+)\(', line))},
'Operations.md': {m.group(1) for line in operations if (m := re.match(r' public enum (\w+)', line))},
'Components.md': {m.group(1) for line in components if (m := schema.match(line))},
}
def documented_symbols(catalog_path):
"""Returns the symbols listed in the DocC catalog topics."""
patterns = {
'APIProtocol.md': r'``(\w+)\(_:\)``',
'Operations.md': r'``Operations/(\w+)``',
'Components.md': r'``Components/Schemas/(\w+)``',
}
return {
name: set(re.findall(pattern, open(f'{catalog_path}/Extensions/{name}').read()))
for name, pattern in patterns.items()
}
def main(generated_path, catalog_path):
generated = generated_symbols(f'{generated_path}/Types.swift')
documented = documented_symbols(catalog_path)
is_up_to_date = True
for name in generated:
missing = sorted(generated[name] - documented[name])
stale = sorted(documented[name] - generated[name])
for title, symbols in [('Missing from', missing), ('Stale in', stale)]:
if symbols:
is_up_to_date = False
print(f'{title} {name} ({len(symbols)}):')
print('\n'.join(f' - {symbol}' for symbol in symbols))
if is_up_to_date:
print('The DocC catalog lists every generated operation and schema.')
return 0 if is_up_to_date else 1
if __name__ == '__main__':
if len(sys.argv) != 3:
sys.exit(__doc__)
sys.exit(main(sys.argv[1], sys.argv[2]))
+39
View File
@@ -0,0 +1,39 @@
# ===------------------------------------------------------------------------------------===
#
# This source file is part of the App Store Connect Service open source project
#
# Copyright (c) 2026 Röck+Cöde VoF. and the App Store Connect Service project authors
# Licensed under Apache license v2.0
#
# See LICENSE for license information
# See CONTRIBUTORS for the list of App Store Connect Service project authors
#
# SPDX-License-Identifier: Apache-2.0
#
# ===------------------------------------------------------------------------------------===
# Patches the App Store Connect OpenAPI specification document. Each patch is safe to apply more than once.
# Removes empty enums (e.g. `fields[appKeywords]`), as they generate case-less Swift enums that do not compile.
(.. | objects | select(.enum == [])) |= del(.enum)
# Adds the undocumented `cursor` query parameter, used by `next` links, to the operations that return paged responses.
| ([
.components.schemas
| to_entries[]
| select(.value.properties.links["$ref"] == "#/components/schemas/PagedDocumentLinks")
| "#/components/schemas/" + .key
]) as $paged
| .paths[][] |= (
if type == "object"
and (.responses["200"].content["application/json"].schema["$ref"] as $ref | any($paged[]; . == $ref))
and (any(.parameters[]?; .name == "cursor") | not)
then .parameters += [{
"name": "cursor",
"in": "query",
"description": "cursor of the page to fetch, from the next link of the previous page",
"schema": { "type": "string" },
"style": "form"
}]
else . end
)
@@ -1,20 +1,28 @@
# ``APIProtocol`` # ``APIProtocol``
A protocol defining the available operations for the App Store Connect API. The operations of the App Store Connect API.
## Overview ## Overview
The ``APIProtocol`` protocol declares the complete set of operations available through the App Store Connect API. Each method corresponds to an HTTP endpoint and follows a consistent naming pattern: Each method calls one endpoint, and is named after its resource followed by its action:
- `<resource>GetCollection` — List resources (HTTP `GET` on a collection) | Suffix | HTTP method | Action |
- `<resource>CreateInstance` — Create a resource (HTTP `POST`) | --- | --- | --- |
- `<resource>GetInstance` — Get a single resource by ID (HTTP `GET`) | `GetCollection` | `GET` | List resources |
- `<resource>UpdateInstance` — Update a resource (HTTP `PATCH`) | `GetInstance` | `GET` | Get a resource by ID |
- `<resource>DeleteInstance` — Delete a resource (HTTP `DELETE`) | `CreateInstance` | `POST` | Create a resource |
- `<resource>GetToManyRelated` — Fetch related resources | `UpdateInstance` | `PATCH` | Update a resource |
- `<resource>GetToOneRelated` — Fetch a related resource | `DeleteInstance` | `DELETE` | Delete a resource |
| `GetToOneRelated`, `GetToManyRelated` | `GET` | Get related resources |
| `GetToOneRelationship`, `GetToManyRelationship` | `GET` | Get the IDs of related resources |
| `CreateToManyRelationship` | `POST` | Add relationships |
| `UpdateToOneRelationship`, `ReplaceToManyRelationship` | `PATCH` | Replace relationships |
| `DeleteToManyRelationship` | `DELETE` | Remove relationships |
| `GetMetrics` | `GET` | Get metrics |
The ``Client`` type conforms to this protocol and provides the concrete implementation for making HTTP requests. For example, ``appsGetCollection(_:)`` lists apps, and ``appsBuildsGetToManyRelated(_:)`` lists the builds of an app.
Every method also has an overload that takes the `path`, `query`, `headers`, and `body` of its `Input` as separate arguments. ``Client`` provides the implementation.
## Topics ## Topics
@@ -106,6 +114,9 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``appsSubscriptionGracePeriodGetToOneRelated(_:)`` - ``appsSubscriptionGracePeriodGetToOneRelated(_:)``
- ``appsSubscriptionGroupsGetToManyRelated(_:)`` - ``appsSubscriptionGroupsGetToManyRelated(_:)``
- ``appsWebhooksGetToManyRelated(_:)`` - ``appsWebhooksGetToManyRelated(_:)``
- ``appsAssetLibraryGetToOneRelationship(_:)``
- ``appsAssetLibraryGetToOneRelated(_:)``
- ``appsPerformanceOverviewsGetToManyRelated(_:)``
- ``appInfosGetInstance(_:)`` - ``appInfosGetInstance(_:)``
- ``appInfosUpdateInstance(_:)`` - ``appInfosUpdateInstance(_:)``
- ``appInfosAgeRatingDeclarationGetToOneRelated(_:)`` - ``appInfosAgeRatingDeclarationGetToOneRelated(_:)``
@@ -207,6 +218,8 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``appStoreVersionLocalizationsSearchKeywordsCreateToManyRelationship(_:)`` - ``appStoreVersionLocalizationsSearchKeywordsCreateToManyRelationship(_:)``
- ``appStoreVersionLocalizationsSearchKeywordsDeleteToManyRelationship(_:)`` - ``appStoreVersionLocalizationsSearchKeywordsDeleteToManyRelationship(_:)``
- ``appStoreVersionLocalizationsSearchKeywordsGetToManyRelated(_:)`` - ``appStoreVersionLocalizationsSearchKeywordsGetToManyRelated(_:)``
- ``appStoreVersionLocalizationsPlacementsGetToManyRelationship(_:)``
- ``appStoreVersionLocalizationsPlacementsGetToManyRelated(_:)``
- ``appStoreVersionPhasedReleasesCreateInstance(_:)`` - ``appStoreVersionPhasedReleasesCreateInstance(_:)``
- ``appStoreVersionPhasedReleasesUpdateInstance(_:)`` - ``appStoreVersionPhasedReleasesUpdateInstance(_:)``
- ``appStoreVersionPhasedReleasesDeleteInstance(_:)`` - ``appStoreVersionPhasedReleasesDeleteInstance(_:)``
@@ -241,6 +254,8 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``appStoreVersionExperimentTreatmentLocalizationsAppScreenshotSetsGetToManyRelated(_:)`` - ``appStoreVersionExperimentTreatmentLocalizationsAppScreenshotSetsGetToManyRelated(_:)``
- ``appStoreVersionExperimentTreatmentLocalizationsAppPreviewSetsGetToManyRelationship(_:)`` - ``appStoreVersionExperimentTreatmentLocalizationsAppPreviewSetsGetToManyRelationship(_:)``
- ``appStoreVersionExperimentTreatmentLocalizationsAppScreenshotSetsGetToManyRelationship(_:)`` - ``appStoreVersionExperimentTreatmentLocalizationsAppScreenshotSetsGetToManyRelationship(_:)``
- ``appStoreVersionExperimentTreatmentLocalizationsPlacementsGetToManyRelationship(_:)``
- ``appStoreVersionExperimentTreatmentLocalizationsPlacementsGetToManyRelated(_:)``
### App Custom Product Pages ### App Custom Product Pages
@@ -267,6 +282,8 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``appCustomProductPageLocalizationsSearchKeywordsCreateToManyRelationship(_:)`` - ``appCustomProductPageLocalizationsSearchKeywordsCreateToManyRelationship(_:)``
- ``appCustomProductPageLocalizationsSearchKeywordsDeleteToManyRelationship(_:)`` - ``appCustomProductPageLocalizationsSearchKeywordsDeleteToManyRelationship(_:)``
- ``appCustomProductPageLocalizationsSearchKeywordsGetToManyRelated(_:)`` - ``appCustomProductPageLocalizationsSearchKeywordsGetToManyRelated(_:)``
- ``appCustomProductPageLocalizationsPlacementsGetToManyRelationship(_:)``
- ``appCustomProductPageLocalizationsPlacementsGetToManyRelated(_:)``
### App Clips ### App Clips
@@ -322,6 +339,8 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``appEventLocalizationsAppEventVideoClipsGetToManyRelated(_:)`` - ``appEventLocalizationsAppEventVideoClipsGetToManyRelated(_:)``
- ``appEventLocalizationsAppEventScreenshotsGetToManyRelationship(_:)`` - ``appEventLocalizationsAppEventScreenshotsGetToManyRelationship(_:)``
- ``appEventLocalizationsAppEventVideoClipsGetToManyRelationship(_:)`` - ``appEventLocalizationsAppEventVideoClipsGetToManyRelationship(_:)``
- ``appEventLocalizationsPlacementsGetToManyRelationship(_:)``
- ``appEventLocalizationsPlacementsGetToManyRelated(_:)``
- ``appEventScreenshotsCreateInstance(_:)`` - ``appEventScreenshotsCreateInstance(_:)``
- ``appEventScreenshotsGetInstance(_:)`` - ``appEventScreenshotsGetInstance(_:)``
- ``appEventScreenshotsUpdateInstance(_:)`` - ``appEventScreenshotsUpdateInstance(_:)``
@@ -358,6 +377,32 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``routingAppCoveragesUpdateInstance(_:)`` - ``routingAppCoveragesUpdateInstance(_:)``
- ``routingAppCoveragesDeleteInstance(_:)`` - ``routingAppCoveragesDeleteInstance(_:)``
### App Asset Library
- ``appAssetLibrariesGetInstance(_:)``
- ``appAssetLibrariesImagesGetToManyRelationship(_:)``
- ``appAssetLibrariesImagesGetToManyRelated(_:)``
- ``appAssetLibrariesVideosGetToManyRelationship(_:)``
- ``appAssetLibrariesVideosGetToManyRelated(_:)``
- ``appAssetLibraryImagesCreateInstance(_:)``
- ``appAssetLibraryImagesGetInstance(_:)``
- ``appAssetLibraryImagesUpdateInstance(_:)``
- ``appAssetLibraryImagesDeleteInstance(_:)``
- ``appAssetLibraryImagesPlacementsGetToManyRelationship(_:)``
- ``appAssetLibraryImagesPlacementsGetToManyRelated(_:)``
- ``appAssetLibraryVideosCreateInstance(_:)``
- ``appAssetLibraryVideosGetInstance(_:)``
- ``appAssetLibraryVideosUpdateInstance(_:)``
- ``appAssetLibraryVideosDeleteInstance(_:)``
- ``appAssetLibraryVideosPlacementsGetToManyRelationship(_:)``
- ``appAssetLibraryVideosPlacementsGetToManyRelated(_:)``
- ``appAssetLibraryPlacementsCreateInstance(_:)``
- ``appAssetLibraryPlacementsGetInstance(_:)``
- ``appAssetLibraryPlacementsDeleteInstance(_:)``
- ``appAssetLibraryPlacementOrderingRequestsCreateInstance(_:)``
- ``appAssetLibraryRefDataGetCollection(_:)``
- ``appAssetLibraryRefDataGetInstance(_:)``
### App Encryption ### App Encryption
- ``appEncryptionDeclarationsGetCollection(_:)`` - ``appEncryptionDeclarationsGetCollection(_:)``
@@ -581,15 +626,33 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``inAppPurchasesV2OfferCodesGetToManyRelationship(_:)`` - ``inAppPurchasesV2OfferCodesGetToManyRelationship(_:)``
- ``inAppPurchasesV2PricePointsGetToManyRelationship(_:)`` - ``inAppPurchasesV2PricePointsGetToManyRelationship(_:)``
- ``inAppPurchasesV2PromotedPurchaseGetToOneRelationship(_:)`` - ``inAppPurchasesV2PromotedPurchaseGetToOneRelationship(_:)``
- ``inAppPurchasesV2VersionsGetToManyRelationship(_:)``
- ``inAppPurchasesV2VersionsGetToManyRelated(_:)``
- ``inAppPurchaseVersionsCreateInstance(_:)``
- ``inAppPurchaseVersionsGetInstance(_:)``
- ``inAppPurchaseVersionsImageGetToOneRelationship(_:)``
- ``inAppPurchaseVersionsImageGetToOneRelated(_:)``
- ``inAppPurchaseVersionsImagesGetToManyRelationship(_:)``
- ``inAppPurchaseVersionsImagesGetToManyRelated(_:)``
- ``inAppPurchaseVersionsLocalizationsGetToManyRelationship(_:)``
- ``inAppPurchaseVersionsLocalizationsGetToManyRelated(_:)``
- ``inAppPurchaseLocalizationsCreateInstance(_:)`` - ``inAppPurchaseLocalizationsCreateInstance(_:)``
- ``inAppPurchaseLocalizationsGetInstance(_:)`` - ``inAppPurchaseLocalizationsGetInstance(_:)``
- ``inAppPurchaseLocalizationsUpdateInstance(_:)`` - ``inAppPurchaseLocalizationsUpdateInstance(_:)``
- ``inAppPurchaseLocalizationsDeleteInstance(_:)`` - ``inAppPurchaseLocalizationsDeleteInstance(_:)``
- ``inAppPurchaseLocalizationsV2CreateInstance(_:)``
- ``inAppPurchaseLocalizationsV2GetInstance(_:)``
- ``inAppPurchaseLocalizationsV2UpdateInstance(_:)``
- ``inAppPurchaseLocalizationsV2DeleteInstance(_:)``
- ``inAppPurchaseContentsGetInstance(_:)`` - ``inAppPurchaseContentsGetInstance(_:)``
- ``inAppPurchaseImagesCreateInstance(_:)`` - ``inAppPurchaseImagesCreateInstance(_:)``
- ``inAppPurchaseImagesGetInstance(_:)`` - ``inAppPurchaseImagesGetInstance(_:)``
- ``inAppPurchaseImagesUpdateInstance(_:)`` - ``inAppPurchaseImagesUpdateInstance(_:)``
- ``inAppPurchaseImagesDeleteInstance(_:)`` - ``inAppPurchaseImagesDeleteInstance(_:)``
- ``inAppPurchaseImagesV2CreateInstance(_:)``
- ``inAppPurchaseImagesV2GetInstance(_:)``
- ``inAppPurchaseImagesV2UpdateInstance(_:)``
- ``inAppPurchaseImagesV2DeleteInstance(_:)``
- ``inAppPurchaseAppStoreReviewScreenshotsCreateInstance(_:)`` - ``inAppPurchaseAppStoreReviewScreenshotsCreateInstance(_:)``
- ``inAppPurchaseAppStoreReviewScreenshotsGetInstance(_:)`` - ``inAppPurchaseAppStoreReviewScreenshotsGetInstance(_:)``
- ``inAppPurchaseAppStoreReviewScreenshotsUpdateInstance(_:)`` - ``inAppPurchaseAppStoreReviewScreenshotsUpdateInstance(_:)``
@@ -660,6 +723,18 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``subscriptionsSubscriptionAvailabilityGetToOneRelated(_:)`` - ``subscriptionsSubscriptionAvailabilityGetToOneRelated(_:)``
- ``subscriptionsSubscriptionLocalizationsGetToManyRelated(_:)`` - ``subscriptionsSubscriptionLocalizationsGetToManyRelated(_:)``
- ``subscriptionsWinBackOffersGetToManyRelated(_:)`` - ``subscriptionsWinBackOffersGetToManyRelated(_:)``
- ``subscriptionsPlanAvailabilitiesGetToManyRelationship(_:)``
- ``subscriptionsPlanAvailabilitiesGetToManyRelated(_:)``
- ``subscriptionsVersionsGetToManyRelationship(_:)``
- ``subscriptionsVersionsGetToManyRelated(_:)``
- ``subscriptionVersionsCreateInstance(_:)``
- ``subscriptionVersionsGetInstance(_:)``
- ``subscriptionVersionsImageGetToOneRelationship(_:)``
- ``subscriptionVersionsImageGetToOneRelated(_:)``
- ``subscriptionVersionsImagesGetToManyRelationship(_:)``
- ``subscriptionVersionsImagesGetToManyRelated(_:)``
- ``subscriptionVersionsLocalizationsGetToManyRelationship(_:)``
- ``subscriptionVersionsLocalizationsGetToManyRelated(_:)``
- ``subscriptionGroupsCreateInstance(_:)`` - ``subscriptionGroupsCreateInstance(_:)``
- ``subscriptionGroupsGetInstance(_:)`` - ``subscriptionGroupsGetInstance(_:)``
- ``subscriptionGroupsUpdateInstance(_:)`` - ``subscriptionGroupsUpdateInstance(_:)``
@@ -668,19 +743,37 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``subscriptionGroupsSubscriptionsGetToManyRelationship(_:)`` - ``subscriptionGroupsSubscriptionsGetToManyRelationship(_:)``
- ``subscriptionGroupsSubscriptionGroupLocalizationsGetToManyRelated(_:)`` - ``subscriptionGroupsSubscriptionGroupLocalizationsGetToManyRelated(_:)``
- ``subscriptionGroupsSubscriptionsGetToManyRelated(_:)`` - ``subscriptionGroupsSubscriptionsGetToManyRelated(_:)``
- ``subscriptionGroupsVersionsGetToManyRelationship(_:)``
- ``subscriptionGroupsVersionsGetToManyRelated(_:)``
- ``subscriptionGroupVersionsCreateInstance(_:)``
- ``subscriptionGroupVersionsGetInstance(_:)``
- ``subscriptionGroupVersionsLocalizationsGetToManyRelationship(_:)``
- ``subscriptionGroupVersionsLocalizationsGetToManyRelated(_:)``
- ``subscriptionGroupLocalizationsCreateInstance(_:)`` - ``subscriptionGroupLocalizationsCreateInstance(_:)``
- ``subscriptionGroupLocalizationsGetInstance(_:)`` - ``subscriptionGroupLocalizationsGetInstance(_:)``
- ``subscriptionGroupLocalizationsUpdateInstance(_:)`` - ``subscriptionGroupLocalizationsUpdateInstance(_:)``
- ``subscriptionGroupLocalizationsDeleteInstance(_:)`` - ``subscriptionGroupLocalizationsDeleteInstance(_:)``
- ``subscriptionGroupLocalizationsV2CreateInstance(_:)``
- ``subscriptionGroupLocalizationsV2GetInstance(_:)``
- ``subscriptionGroupLocalizationsV2UpdateInstance(_:)``
- ``subscriptionGroupLocalizationsV2DeleteInstance(_:)``
- ``subscriptionGroupSubmissionsCreateInstance(_:)`` - ``subscriptionGroupSubmissionsCreateInstance(_:)``
- ``subscriptionLocalizationsCreateInstance(_:)`` - ``subscriptionLocalizationsCreateInstance(_:)``
- ``subscriptionLocalizationsGetInstance(_:)`` - ``subscriptionLocalizationsGetInstance(_:)``
- ``subscriptionLocalizationsUpdateInstance(_:)`` - ``subscriptionLocalizationsUpdateInstance(_:)``
- ``subscriptionLocalizationsDeleteInstance(_:)`` - ``subscriptionLocalizationsDeleteInstance(_:)``
- ``subscriptionLocalizationsV2CreateInstance(_:)``
- ``subscriptionLocalizationsV2GetInstance(_:)``
- ``subscriptionLocalizationsV2UpdateInstance(_:)``
- ``subscriptionLocalizationsV2DeleteInstance(_:)``
- ``subscriptionImagesCreateInstance(_:)`` - ``subscriptionImagesCreateInstance(_:)``
- ``subscriptionImagesGetInstance(_:)`` - ``subscriptionImagesGetInstance(_:)``
- ``subscriptionImagesUpdateInstance(_:)`` - ``subscriptionImagesUpdateInstance(_:)``
- ``subscriptionImagesDeleteInstance(_:)`` - ``subscriptionImagesDeleteInstance(_:)``
- ``subscriptionImagesV2CreateInstance(_:)``
- ``subscriptionImagesV2GetInstance(_:)``
- ``subscriptionImagesV2UpdateInstance(_:)``
- ``subscriptionImagesV2DeleteInstance(_:)``
- ``subscriptionAppStoreReviewScreenshotsCreateInstance(_:)`` - ``subscriptionAppStoreReviewScreenshotsCreateInstance(_:)``
- ``subscriptionAppStoreReviewScreenshotsGetInstance(_:)`` - ``subscriptionAppStoreReviewScreenshotsGetInstance(_:)``
- ``subscriptionAppStoreReviewScreenshotsUpdateInstance(_:)`` - ``subscriptionAppStoreReviewScreenshotsUpdateInstance(_:)``
@@ -689,6 +782,12 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``subscriptionAvailabilitiesGetInstance(_:)`` - ``subscriptionAvailabilitiesGetInstance(_:)``
- ``subscriptionAvailabilitiesAvailableTerritoriesGetToManyRelated(_:)`` - ``subscriptionAvailabilitiesAvailableTerritoriesGetToManyRelated(_:)``
- ``subscriptionAvailabilitiesAvailableTerritoriesGetToManyRelationship(_:)`` - ``subscriptionAvailabilitiesAvailableTerritoriesGetToManyRelationship(_:)``
- ``subscriptionPlanAvailabilitiesCreateInstance(_:)``
- ``subscriptionPlanAvailabilitiesGetInstance(_:)``
- ``subscriptionPlanAvailabilitiesUpdateInstance(_:)``
- ``subscriptionPlanAvailabilitiesAvailableTerritoriesGetToManyRelationship(_:)``
- ``subscriptionPlanAvailabilitiesAvailableTerritoriesReplaceToManyRelationship(_:)``
- ``subscriptionPlanAvailabilitiesAvailableTerritoriesGetToManyRelated(_:)``
- ``subscriptionGracePeriodsGetInstance(_:)`` - ``subscriptionGracePeriodsGetInstance(_:)``
- ``subscriptionGracePeriodsUpdateInstance(_:)`` - ``subscriptionGracePeriodsUpdateInstance(_:)``
- ``subscriptionIntroductoryOffersCreateInstance(_:)`` - ``subscriptionIntroductoryOffersCreateInstance(_:)``
@@ -713,6 +812,7 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``subscriptionPricePointsGetInstance(_:)`` - ``subscriptionPricePointsGetInstance(_:)``
- ``subscriptionPricePointsEqualizationsGetToManyRelated(_:)`` - ``subscriptionPricePointsEqualizationsGetToManyRelated(_:)``
- ``subscriptionPricePointsEqualizationsGetToManyRelationship(_:)`` - ``subscriptionPricePointsEqualizationsGetToManyRelationship(_:)``
- ``subscriptionPricePointsAdjustedEqualizationsGetToManyRelated(_:)``
- ``subscriptionPricesCreateInstance(_:)`` - ``subscriptionPricesCreateInstance(_:)``
- ``subscriptionPricesDeleteInstance(_:)`` - ``subscriptionPricesDeleteInstance(_:)``
- ``subscriptionPromotionalOffersCreateInstance(_:)`` - ``subscriptionPromotionalOffersCreateInstance(_:)``
@@ -773,6 +873,9 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``gameCenterDetailsGameCenterLeaderboardsV2ReplaceToManyRelationship(_:)`` - ``gameCenterDetailsGameCenterLeaderboardsV2ReplaceToManyRelationship(_:)``
- ``gameCenterDetailsLeaderboardReleasesGetToManyRelationship(_:)`` - ``gameCenterDetailsLeaderboardReleasesGetToManyRelationship(_:)``
- ``gameCenterDetailsLeaderboardSetReleasesGetToManyRelationship(_:)`` - ``gameCenterDetailsLeaderboardSetReleasesGetToManyRelationship(_:)``
- ``gameCenterDetailsBlockedPlayersGetToManyRelationship(_:)``
- ``gameCenterDetailsBlockedPlayersGetToManyRelated(_:)``
- ``gameCenterDetailPlayersUpdateInstance(_:)``
- ``gameCenterGroupsGetCollection(_:)`` - ``gameCenterGroupsGetCollection(_:)``
- ``gameCenterGroupsCreateInstance(_:)`` - ``gameCenterGroupsCreateInstance(_:)``
- ``gameCenterGroupsGetInstance(_:)`` - ``gameCenterGroupsGetInstance(_:)``
@@ -871,6 +974,9 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``gameCenterLeaderboardsV2ChallengeUpdateToOneRelationship(_:)`` - ``gameCenterLeaderboardsV2ChallengeUpdateToOneRelationship(_:)``
- ``gameCenterLeaderboardsV2VersionsGetToManyRelationship(_:)`` - ``gameCenterLeaderboardsV2VersionsGetToManyRelationship(_:)``
- ``gameCenterLeaderboardsV2VersionsGetToManyRelated(_:)`` - ``gameCenterLeaderboardsV2VersionsGetToManyRelated(_:)``
- ``gameCenterLeaderboardsV2GameCenterScoreModerationsGetToManyRelationship(_:)``
- ``gameCenterLeaderboardsV2GameCenterScoreModerationsGetToManyRelated(_:)``
- ``gameCenterScoreModerationsUpdateInstance(_:)``
- ``gameCenterLeaderboardVersionsV2CreateInstance(_:)`` - ``gameCenterLeaderboardVersionsV2CreateInstance(_:)``
- ``gameCenterLeaderboardVersionsV2GetInstance(_:)`` - ``gameCenterLeaderboardVersionsV2GetInstance(_:)``
- ``gameCenterLeaderboardVersionsV2LocalizationsGetToManyRelated(_:)`` - ``gameCenterLeaderboardVersionsV2LocalizationsGetToManyRelated(_:)``
@@ -1,21 +1,19 @@
# ``Client`` # ``Client``
The API client for performing HTTP operations against the App Store Connect API. The App Store Connect API client.
## Overview ## Overview
The ``Client`` struct is the main entry point for interacting with the App Store Connect API. It conforms to ``APIProtocol`` and provides concrete implementations for all available API operations. ``Client`` implements every ``APIProtocol`` method by sending the request through its transport, after passing it through its middlewares.
### Creating a Client Include ``BearerAuthMiddleware`` in `middlewares` to authenticate requests:
Create a ``Client`` by providing a server URL, a transport, and optionally a list of middlewares for authentication or request customization.
```swift ```swift
import ASConnectService import ASConnectService
import OpenAPIURLSession import OpenAPIURLSession
let client = Client( let client = Client(
serverURL: try Servers.server1(), serverURL: try Servers.Server1.url(),
transport: URLSessionTransport(), transport: URLSessionTransport(),
middlewares: [ middlewares: [
BearerAuthMiddleware(token: yourJWTToken) BearerAuthMiddleware(token: yourJWTToken)
@@ -23,12 +21,10 @@ let client = Client(
) )
``` ```
### Making API Calls Each method takes either a single `Input` value or its `path`, `query`, `headers`, and `body` as separate arguments:
Each method on the ``Client`` corresponds to an HTTP endpoint defined in the App Store Connect API OpenAPI specification. Methods accept an `Input` value and return an `Output` value representing the response.
```swift ```swift
let response = try await client.appsGetCollection(.init()) let response = try await client.appsGetInstance(path: .init(id: appID))
``` ```
## Topics ## Topics
@@ -1,17 +1,16 @@
# ``Components`` # ``Components``
Types generated from the components section of the OpenAPI document. The data models of the App Store Connect API.
## Overview ## Overview
The ``Components`` namespace contains all the data models defined in the App Store Connect API OpenAPI specification. These types are organized within the ``Components/Schemas`` namespace and are used as request and response bodies across all API operations. The models are in ``Components/Schemas``, and are used as request and response bodies. Each resource typically has:
Each resource type typically includes: - A model, such as ``Components/Schemas/App``.
- A single-resource response, such as ``Components/Schemas/AppResponse``.
- A **model type** (e.g., `Components.Schemas.App`) representing the resource - A collection response, such as ``Components/Schemas/AppsResponse``.
- A **response type** (e.g., `Components.Schemas.AppResponse`) for single-resource responses - Create and update requests, such as ``Components/Schemas/AppUpdateRequest``.
- A **collection response type** (e.g., `Components.Schemas.AppsResponse`) for list responses - Linkage responses for its relationships, such as ``Components/Schemas/AppBuildsLinkagesResponse``.
- **Request types** for create and update operations (e.g., `Components.Schemas.AppUpdateRequest`)
## Topics ## Topics
@@ -94,6 +93,7 @@ Each resource type typically includes:
- ``Components/Schemas/AppMediaStateError`` - ``Components/Schemas/AppMediaStateError``
- ``Components/Schemas/AppMediaVideoState`` - ``Components/Schemas/AppMediaVideoState``
- ``Components/Schemas/AppPerfPowerMetricsLinkagesResponse`` - ``Components/Schemas/AppPerfPowerMetricsLinkagesResponse``
- ``Components/Schemas/AppPerformanceOverviewsLinkagesResponse``
- ``Components/Schemas/AppPreReleaseVersionsLinkagesResponse`` - ``Components/Schemas/AppPreReleaseVersionsLinkagesResponse``
- ``Components/Schemas/AppPricePointV3`` - ``Components/Schemas/AppPricePointV3``
- ``Components/Schemas/AppPricePointV3EqualizationsLinkagesResponse`` - ``Components/Schemas/AppPricePointV3EqualizationsLinkagesResponse``
@@ -156,6 +156,7 @@ Each resource type typically includes:
- ``Components/Schemas/AppStoreVersionLocalizationAppPreviewSetsLinkagesResponse`` - ``Components/Schemas/AppStoreVersionLocalizationAppPreviewSetsLinkagesResponse``
- ``Components/Schemas/AppStoreVersionLocalizationAppScreenshotSetsLinkagesResponse`` - ``Components/Schemas/AppStoreVersionLocalizationAppScreenshotSetsLinkagesResponse``
- ``Components/Schemas/AppStoreVersionLocalizationCreateRequest`` - ``Components/Schemas/AppStoreVersionLocalizationCreateRequest``
- ``Components/Schemas/AppStoreVersionLocalizationPlacementsLinkagesResponse``
- ``Components/Schemas/AppStoreVersionLocalizationResponse`` - ``Components/Schemas/AppStoreVersionLocalizationResponse``
- ``Components/Schemas/AppStoreVersionLocalizationSearchKeywordsLinkagesRequest`` - ``Components/Schemas/AppStoreVersionLocalizationSearchKeywordsLinkagesRequest``
- ``Components/Schemas/AppStoreVersionLocalizationSearchKeywordsLinkagesResponse`` - ``Components/Schemas/AppStoreVersionLocalizationSearchKeywordsLinkagesResponse``
@@ -194,6 +195,7 @@ Each resource type typically includes:
- ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationAppPreviewSetsLinkagesResponse`` - ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationAppPreviewSetsLinkagesResponse``
- ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationAppScreenshotSetsLinkagesResponse`` - ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationAppScreenshotSetsLinkagesResponse``
- ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationCreateRequest`` - ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationCreateRequest``
- ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationPlacementsLinkagesResponse``
- ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationResponse`` - ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationResponse``
- ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationsResponse`` - ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationsResponse``
- ``Components/Schemas/AppStoreVersionExperimentTreatmentResponse`` - ``Components/Schemas/AppStoreVersionExperimentTreatmentResponse``
@@ -218,6 +220,7 @@ Each resource type typically includes:
- ``Components/Schemas/AppCustomProductPageLocalizationAppScreenshotSetsLinkagesResponse`` - ``Components/Schemas/AppCustomProductPageLocalizationAppScreenshotSetsLinkagesResponse``
- ``Components/Schemas/AppCustomProductPageLocalizationCreateRequest`` - ``Components/Schemas/AppCustomProductPageLocalizationCreateRequest``
- ``Components/Schemas/AppCustomProductPageLocalizationInlineCreate`` - ``Components/Schemas/AppCustomProductPageLocalizationInlineCreate``
- ``Components/Schemas/AppCustomProductPageLocalizationPlacementsLinkagesResponse``
- ``Components/Schemas/AppCustomProductPageLocalizationResponse`` - ``Components/Schemas/AppCustomProductPageLocalizationResponse``
- ``Components/Schemas/AppCustomProductPageLocalizationSearchKeywordsLinkagesRequest`` - ``Components/Schemas/AppCustomProductPageLocalizationSearchKeywordsLinkagesRequest``
- ``Components/Schemas/AppCustomProductPageLocalizationSearchKeywordsLinkagesResponse`` - ``Components/Schemas/AppCustomProductPageLocalizationSearchKeywordsLinkagesResponse``
@@ -289,6 +292,7 @@ Each resource type typically includes:
- ``Components/Schemas/AppEventLocalizationAppEventScreenshotsLinkagesResponse`` - ``Components/Schemas/AppEventLocalizationAppEventScreenshotsLinkagesResponse``
- ``Components/Schemas/AppEventLocalizationAppEventVideoClipsLinkagesResponse`` - ``Components/Schemas/AppEventLocalizationAppEventVideoClipsLinkagesResponse``
- ``Components/Schemas/AppEventLocalizationCreateRequest`` - ``Components/Schemas/AppEventLocalizationCreateRequest``
- ``Components/Schemas/AppEventLocalizationPlacementsLinkagesResponse``
- ``Components/Schemas/AppEventLocalizationResponse`` - ``Components/Schemas/AppEventLocalizationResponse``
- ``Components/Schemas/AppEventLocalizationUpdateRequest`` - ``Components/Schemas/AppEventLocalizationUpdateRequest``
- ``Components/Schemas/AppEventLocalizationsLinkagesResponse`` - ``Components/Schemas/AppEventLocalizationsLinkagesResponse``
@@ -337,6 +341,71 @@ Each resource type typically includes:
- ``Components/Schemas/RoutingAppCoverageResponse`` - ``Components/Schemas/RoutingAppCoverageResponse``
- ``Components/Schemas/RoutingAppCoverageUpdateRequest`` - ``Components/Schemas/RoutingAppCoverageUpdateRequest``
### App Asset Library
- ``Components/Schemas/AppAssetLibrary``
- ``Components/Schemas/AppAssetLibraryAssetCategory``
- ``Components/Schemas/AppAssetLibraryAssetState``
- ``Components/Schemas/AppAssetLibraryDisplayClass``
- ``Components/Schemas/AppAssetLibraryFeature``
- ``Components/Schemas/AppAssetLibraryImage``
- ``Components/Schemas/AppAssetLibraryImageAcceptedAttributes``
- ``Components/Schemas/AppAssetLibraryImageApprovedAttributes``
- ``Components/Schemas/AppAssetLibraryImageArchivedAttributes``
- ``Components/Schemas/AppAssetLibraryImageAwaitingUploadAttributes``
- ``Components/Schemas/AppAssetLibraryImageCommonAttributes``
- ``Components/Schemas/AppAssetLibraryImageCreateRequest``
- ``Components/Schemas/AppAssetLibraryImageFailedAttributes``
- ``Components/Schemas/AppAssetLibraryImageInReviewAttributes``
- ``Components/Schemas/AppAssetLibraryImagePlacementsLinkagesResponse``
- ``Components/Schemas/AppAssetLibraryImageReadyForReviewAttributes``
- ``Components/Schemas/AppAssetLibraryImageRejectedAttributes``
- ``Components/Schemas/AppAssetLibraryImageResponse``
- ``Components/Schemas/AppAssetLibraryImageUpdateRequest``
- ``Components/Schemas/AppAssetLibraryImageUploadCompleteAttributes``
- ``Components/Schemas/AppAssetLibraryImageWaitingForReviewAttributes``
- ``Components/Schemas/AppAssetLibraryImagesLinkagesResponse``
- ``Components/Schemas/AppAssetLibraryImagesResponse``
- ``Components/Schemas/AppAssetLibraryLinkageResponse``
- ``Components/Schemas/AppAssetLibraryMediaType``
- ``Components/Schemas/AppAssetLibraryPlacement``
- ``Components/Schemas/AppAssetLibraryPlacementCommonAttributes``
- ``Components/Schemas/AppAssetLibraryPlacementCommonRelationships``
- ``Components/Schemas/AppAssetLibraryPlacementCreateRequest``
- ``Components/Schemas/AppAssetLibraryPlacementImageRelationships``
- ``Components/Schemas/AppAssetLibraryPlacementOrderingRequest``
- ``Components/Schemas/AppAssetLibraryPlacementOrderingRequestCreateRequest``
- ``Components/Schemas/AppAssetLibraryPlacementOrderingRequestResponse``
- ``Components/Schemas/AppAssetLibraryPlacementPlatform``
- ``Components/Schemas/AppAssetLibraryPlacementResponse``
- ``Components/Schemas/AppAssetLibraryPlacementState``
- ``Components/Schemas/AppAssetLibraryPlacementType``
- ``Components/Schemas/AppAssetLibraryPlacementVideoAttributes``
- ``Components/Schemas/AppAssetLibraryPlacementVideoRelationships``
- ``Components/Schemas/AppAssetLibraryPlacementsResponse``
- ``Components/Schemas/AppAssetLibraryRefDataResponse``
- ``Components/Schemas/AppAssetLibraryRefDatum``
- ``Components/Schemas/AppAssetLibraryRefDatumResponse``
- ``Components/Schemas/AppAssetLibraryResponse``
- ``Components/Schemas/AppAssetLibraryVideo``
- ``Components/Schemas/AppAssetLibraryVideoAcceptedAttributes``
- ``Components/Schemas/AppAssetLibraryVideoApprovedAttributes``
- ``Components/Schemas/AppAssetLibraryVideoArchivedAttributes``
- ``Components/Schemas/AppAssetLibraryVideoAwaitingUploadAttributes``
- ``Components/Schemas/AppAssetLibraryVideoCommonAttributes``
- ``Components/Schemas/AppAssetLibraryVideoCreateRequest``
- ``Components/Schemas/AppAssetLibraryVideoFailedAttributes``
- ``Components/Schemas/AppAssetLibraryVideoInReviewAttributes``
- ``Components/Schemas/AppAssetLibraryVideoPlacementsLinkagesResponse``
- ``Components/Schemas/AppAssetLibraryVideoReadyForReviewAttributes``
- ``Components/Schemas/AppAssetLibraryVideoRejectedAttributes``
- ``Components/Schemas/AppAssetLibraryVideoResponse``
- ``Components/Schemas/AppAssetLibraryVideoUpdateRequest``
- ``Components/Schemas/AppAssetLibraryVideoUploadCompleteAttributes``
- ``Components/Schemas/AppAssetLibraryVideoWaitingForReviewAttributes``
- ``Components/Schemas/AppAssetLibraryVideosLinkagesResponse``
- ``Components/Schemas/AppAssetLibraryVideosResponse``
### App Encryption ### App Encryption
- ``Components/Schemas/AppEncryptionDeclaration`` - ``Components/Schemas/AppEncryptionDeclaration``
@@ -573,12 +642,22 @@ Each resource type typically includes:
- ``Components/Schemas/InAppPurchaseImageCreateRequest`` - ``Components/Schemas/InAppPurchaseImageCreateRequest``
- ``Components/Schemas/InAppPurchaseImageResponse`` - ``Components/Schemas/InAppPurchaseImageResponse``
- ``Components/Schemas/InAppPurchaseImageUpdateRequest`` - ``Components/Schemas/InAppPurchaseImageUpdateRequest``
- ``Components/Schemas/InAppPurchaseImageV2``
- ``Components/Schemas/InAppPurchaseImageV2CreateRequest``
- ``Components/Schemas/InAppPurchaseImageV2Response``
- ``Components/Schemas/InAppPurchaseImageV2UpdateRequest``
- ``Components/Schemas/InAppPurchaseImagesResponse`` - ``Components/Schemas/InAppPurchaseImagesResponse``
- ``Components/Schemas/InAppPurchaseImagesV2Response``
- ``Components/Schemas/InAppPurchaseLocalization`` - ``Components/Schemas/InAppPurchaseLocalization``
- ``Components/Schemas/InAppPurchaseLocalizationCreateRequest`` - ``Components/Schemas/InAppPurchaseLocalizationCreateRequest``
- ``Components/Schemas/InAppPurchaseLocalizationResponse`` - ``Components/Schemas/InAppPurchaseLocalizationResponse``
- ``Components/Schemas/InAppPurchaseLocalizationUpdateRequest`` - ``Components/Schemas/InAppPurchaseLocalizationUpdateRequest``
- ``Components/Schemas/InAppPurchaseLocalizationV2``
- ``Components/Schemas/InAppPurchaseLocalizationV2CreateRequest``
- ``Components/Schemas/InAppPurchaseLocalizationV2Response``
- ``Components/Schemas/InAppPurchaseLocalizationV2UpdateRequest``
- ``Components/Schemas/InAppPurchaseLocalizationsResponse`` - ``Components/Schemas/InAppPurchaseLocalizationsResponse``
- ``Components/Schemas/InAppPurchaseLocalizationsV2Response``
- ``Components/Schemas/InAppPurchaseOfferCode`` - ``Components/Schemas/InAppPurchaseOfferCode``
- ``Components/Schemas/InAppPurchaseOfferCodeCreateRequest`` - ``Components/Schemas/InAppPurchaseOfferCodeCreateRequest``
- ``Components/Schemas/InAppPurchaseOfferCodeCustomCode`` - ``Components/Schemas/InAppPurchaseOfferCodeCustomCode``
@@ -633,6 +712,14 @@ Each resource type typically includes:
- ``Components/Schemas/InAppPurchaseV2PromotedPurchaseLinkageResponse`` - ``Components/Schemas/InAppPurchaseV2PromotedPurchaseLinkageResponse``
- ``Components/Schemas/InAppPurchaseV2Response`` - ``Components/Schemas/InAppPurchaseV2Response``
- ``Components/Schemas/InAppPurchaseV2UpdateRequest`` - ``Components/Schemas/InAppPurchaseV2UpdateRequest``
- ``Components/Schemas/InAppPurchaseV2VersionsLinkagesResponse``
- ``Components/Schemas/InAppPurchaseVersion``
- ``Components/Schemas/InAppPurchaseVersionCreateRequest``
- ``Components/Schemas/InAppPurchaseVersionImageLinkageResponse``
- ``Components/Schemas/InAppPurchaseVersionImagesLinkagesResponse``
- ``Components/Schemas/InAppPurchaseVersionLocalizationsLinkagesResponse``
- ``Components/Schemas/InAppPurchaseVersionResponse``
- ``Components/Schemas/InAppPurchaseVersionsResponse``
- ``Components/Schemas/InAppPurchasesResponse`` - ``Components/Schemas/InAppPurchasesResponse``
- ``Components/Schemas/InAppPurchasesV2Response`` - ``Components/Schemas/InAppPurchasesV2Response``
- ``Components/Schemas/OfferCodeEnvironment`` - ``Components/Schemas/OfferCodeEnvironment``
@@ -666,7 +753,12 @@ Each resource type typically includes:
- ``Components/Schemas/SubscriptionGroupLocalizationCreateRequest`` - ``Components/Schemas/SubscriptionGroupLocalizationCreateRequest``
- ``Components/Schemas/SubscriptionGroupLocalizationResponse`` - ``Components/Schemas/SubscriptionGroupLocalizationResponse``
- ``Components/Schemas/SubscriptionGroupLocalizationUpdateRequest`` - ``Components/Schemas/SubscriptionGroupLocalizationUpdateRequest``
- ``Components/Schemas/SubscriptionGroupLocalizationV2``
- ``Components/Schemas/SubscriptionGroupLocalizationV2CreateRequest``
- ``Components/Schemas/SubscriptionGroupLocalizationV2Response``
- ``Components/Schemas/SubscriptionGroupLocalizationV2UpdateRequest``
- ``Components/Schemas/SubscriptionGroupLocalizationsResponse`` - ``Components/Schemas/SubscriptionGroupLocalizationsResponse``
- ``Components/Schemas/SubscriptionGroupLocalizationsV2Response``
- ``Components/Schemas/SubscriptionGroupResponse`` - ``Components/Schemas/SubscriptionGroupResponse``
- ``Components/Schemas/SubscriptionGroupSubmission`` - ``Components/Schemas/SubscriptionGroupSubmission``
- ``Components/Schemas/SubscriptionGroupSubmissionCreateRequest`` - ``Components/Schemas/SubscriptionGroupSubmissionCreateRequest``
@@ -674,13 +766,24 @@ Each resource type typically includes:
- ``Components/Schemas/SubscriptionGroupSubscriptionGroupLocalizationsLinkagesResponse`` - ``Components/Schemas/SubscriptionGroupSubscriptionGroupLocalizationsLinkagesResponse``
- ``Components/Schemas/SubscriptionGroupSubscriptionsLinkagesResponse`` - ``Components/Schemas/SubscriptionGroupSubscriptionsLinkagesResponse``
- ``Components/Schemas/SubscriptionGroupUpdateRequest`` - ``Components/Schemas/SubscriptionGroupUpdateRequest``
- ``Components/Schemas/SubscriptionGroupVersion``
- ``Components/Schemas/SubscriptionGroupVersionCreateRequest``
- ``Components/Schemas/SubscriptionGroupVersionLocalizationsLinkagesResponse``
- ``Components/Schemas/SubscriptionGroupVersionResponse``
- ``Components/Schemas/SubscriptionGroupVersionsLinkagesResponse``
- ``Components/Schemas/SubscriptionGroupVersionsResponse``
- ``Components/Schemas/SubscriptionGroupsResponse`` - ``Components/Schemas/SubscriptionGroupsResponse``
- ``Components/Schemas/SubscriptionImage`` - ``Components/Schemas/SubscriptionImage``
- ``Components/Schemas/SubscriptionImageCreateRequest`` - ``Components/Schemas/SubscriptionImageCreateRequest``
- ``Components/Schemas/SubscriptionImageResponse`` - ``Components/Schemas/SubscriptionImageResponse``
- ``Components/Schemas/SubscriptionImageUpdateRequest`` - ``Components/Schemas/SubscriptionImageUpdateRequest``
- ``Components/Schemas/SubscriptionImageV2``
- ``Components/Schemas/SubscriptionImageV2CreateRequest``
- ``Components/Schemas/SubscriptionImageV2Response``
- ``Components/Schemas/SubscriptionImageV2UpdateRequest``
- ``Components/Schemas/SubscriptionImagesLinkagesResponse`` - ``Components/Schemas/SubscriptionImagesLinkagesResponse``
- ``Components/Schemas/SubscriptionImagesResponse`` - ``Components/Schemas/SubscriptionImagesResponse``
- ``Components/Schemas/SubscriptionImagesV2Response``
- ``Components/Schemas/SubscriptionIntroductoryOffer`` - ``Components/Schemas/SubscriptionIntroductoryOffer``
- ``Components/Schemas/SubscriptionIntroductoryOfferCreateRequest`` - ``Components/Schemas/SubscriptionIntroductoryOfferCreateRequest``
- ``Components/Schemas/SubscriptionIntroductoryOfferInlineCreate`` - ``Components/Schemas/SubscriptionIntroductoryOfferInlineCreate``
@@ -693,7 +796,12 @@ Each resource type typically includes:
- ``Components/Schemas/SubscriptionLocalizationCreateRequest`` - ``Components/Schemas/SubscriptionLocalizationCreateRequest``
- ``Components/Schemas/SubscriptionLocalizationResponse`` - ``Components/Schemas/SubscriptionLocalizationResponse``
- ``Components/Schemas/SubscriptionLocalizationUpdateRequest`` - ``Components/Schemas/SubscriptionLocalizationUpdateRequest``
- ``Components/Schemas/SubscriptionLocalizationV2``
- ``Components/Schemas/SubscriptionLocalizationV2CreateRequest``
- ``Components/Schemas/SubscriptionLocalizationV2Response``
- ``Components/Schemas/SubscriptionLocalizationV2UpdateRequest``
- ``Components/Schemas/SubscriptionLocalizationsResponse`` - ``Components/Schemas/SubscriptionLocalizationsResponse``
- ``Components/Schemas/SubscriptionLocalizationsV2Response``
- ``Components/Schemas/SubscriptionOfferCode`` - ``Components/Schemas/SubscriptionOfferCode``
- ``Components/Schemas/SubscriptionOfferCodeCreateRequest`` - ``Components/Schemas/SubscriptionOfferCodeCreateRequest``
- ``Components/Schemas/SubscriptionOfferCodeCustomCode`` - ``Components/Schemas/SubscriptionOfferCodeCustomCode``
@@ -721,6 +829,15 @@ Each resource type typically includes:
- ``Components/Schemas/SubscriptionOfferDuration`` - ``Components/Schemas/SubscriptionOfferDuration``
- ``Components/Schemas/SubscriptionOfferEligibility`` - ``Components/Schemas/SubscriptionOfferEligibility``
- ``Components/Schemas/SubscriptionOfferMode`` - ``Components/Schemas/SubscriptionOfferMode``
- ``Components/Schemas/SubscriptionPlanAvailabilitiesLinkagesResponse``
- ``Components/Schemas/SubscriptionPlanAvailabilitiesResponse``
- ``Components/Schemas/SubscriptionPlanAvailability``
- ``Components/Schemas/SubscriptionPlanAvailabilityAvailableTerritoriesLinkagesRequest``
- ``Components/Schemas/SubscriptionPlanAvailabilityAvailableTerritoriesLinkagesResponse``
- ``Components/Schemas/SubscriptionPlanAvailabilityCreateRequest``
- ``Components/Schemas/SubscriptionPlanAvailabilityResponse``
- ``Components/Schemas/SubscriptionPlanAvailabilityUpdateRequest``
- ``Components/Schemas/SubscriptionPlanType``
- ``Components/Schemas/SubscriptionPrice`` - ``Components/Schemas/SubscriptionPrice``
- ``Components/Schemas/SubscriptionPriceCreateRequest`` - ``Components/Schemas/SubscriptionPriceCreateRequest``
- ``Components/Schemas/SubscriptionPriceInlineCreate`` - ``Components/Schemas/SubscriptionPriceInlineCreate``
@@ -754,6 +871,14 @@ Each resource type typically includes:
- ``Components/Schemas/SubscriptionSubscriptionAvailabilityLinkageResponse`` - ``Components/Schemas/SubscriptionSubscriptionAvailabilityLinkageResponse``
- ``Components/Schemas/SubscriptionSubscriptionLocalizationsLinkagesResponse`` - ``Components/Schemas/SubscriptionSubscriptionLocalizationsLinkagesResponse``
- ``Components/Schemas/SubscriptionUpdateRequest`` - ``Components/Schemas/SubscriptionUpdateRequest``
- ``Components/Schemas/SubscriptionVersion``
- ``Components/Schemas/SubscriptionVersionCreateRequest``
- ``Components/Schemas/SubscriptionVersionImageLinkageResponse``
- ``Components/Schemas/SubscriptionVersionImagesLinkagesResponse``
- ``Components/Schemas/SubscriptionVersionLocalizationsLinkagesResponse``
- ``Components/Schemas/SubscriptionVersionResponse``
- ``Components/Schemas/SubscriptionVersionsLinkagesResponse``
- ``Components/Schemas/SubscriptionVersionsResponse``
- ``Components/Schemas/SubscriptionWinBackOffersLinkagesResponse`` - ``Components/Schemas/SubscriptionWinBackOffersLinkagesResponse``
- ``Components/Schemas/SubscriptionsResponse`` - ``Components/Schemas/SubscriptionsResponse``
- ``Components/Schemas/WinBackOffer`` - ``Components/Schemas/WinBackOffer``
@@ -888,6 +1013,7 @@ Each resource type typically includes:
- ``Components/Schemas/GameCenterDetail`` - ``Components/Schemas/GameCenterDetail``
- ``Components/Schemas/GameCenterDetailAchievementReleasesLinkagesResponse`` - ``Components/Schemas/GameCenterDetailAchievementReleasesLinkagesResponse``
- ``Components/Schemas/GameCenterDetailActivityReleasesLinkagesResponse`` - ``Components/Schemas/GameCenterDetailActivityReleasesLinkagesResponse``
- ``Components/Schemas/GameCenterDetailBlockedPlayersLinkagesResponse``
- ``Components/Schemas/GameCenterDetailChallengeReleasesLinkagesResponse`` - ``Components/Schemas/GameCenterDetailChallengeReleasesLinkagesResponse``
- ``Components/Schemas/GameCenterDetailChallengesMinimumPlatformVersionsLinkagesRequest`` - ``Components/Schemas/GameCenterDetailChallengesMinimumPlatformVersionsLinkagesRequest``
- ``Components/Schemas/GameCenterDetailCreateRequest`` - ``Components/Schemas/GameCenterDetailCreateRequest``
@@ -909,6 +1035,10 @@ Each resource type typically includes:
- ``Components/Schemas/GameCenterDetailGameCenterLeaderboardsV2LinkagesResponse`` - ``Components/Schemas/GameCenterDetailGameCenterLeaderboardsV2LinkagesResponse``
- ``Components/Schemas/GameCenterDetailLeaderboardReleasesLinkagesResponse`` - ``Components/Schemas/GameCenterDetailLeaderboardReleasesLinkagesResponse``
- ``Components/Schemas/GameCenterDetailLeaderboardSetReleasesLinkagesResponse`` - ``Components/Schemas/GameCenterDetailLeaderboardSetReleasesLinkagesResponse``
- ``Components/Schemas/GameCenterDetailPlayer``
- ``Components/Schemas/GameCenterDetailPlayerResponse``
- ``Components/Schemas/GameCenterDetailPlayerUpdateRequest``
- ``Components/Schemas/GameCenterDetailPlayersResponse``
- ``Components/Schemas/GameCenterDetailResponse`` - ``Components/Schemas/GameCenterDetailResponse``
- ``Components/Schemas/GameCenterDetailUpdateRequest`` - ``Components/Schemas/GameCenterDetailUpdateRequest``
- ``Components/Schemas/GameCenterDetailsResponse`` - ``Components/Schemas/GameCenterDetailsResponse``
@@ -1034,6 +1164,7 @@ Each resource type typically includes:
- ``Components/Schemas/GameCenterLeaderboardV2ActivityLinkageRequest`` - ``Components/Schemas/GameCenterLeaderboardV2ActivityLinkageRequest``
- ``Components/Schemas/GameCenterLeaderboardV2ChallengeLinkageRequest`` - ``Components/Schemas/GameCenterLeaderboardV2ChallengeLinkageRequest``
- ``Components/Schemas/GameCenterLeaderboardV2CreateRequest`` - ``Components/Schemas/GameCenterLeaderboardV2CreateRequest``
- ``Components/Schemas/GameCenterLeaderboardV2GameCenterScoreModerationsLinkagesResponse``
- ``Components/Schemas/GameCenterLeaderboardV2Response`` - ``Components/Schemas/GameCenterLeaderboardV2Response``
- ``Components/Schemas/GameCenterLeaderboardV2UpdateRequest`` - ``Components/Schemas/GameCenterLeaderboardV2UpdateRequest``
- ``Components/Schemas/GameCenterLeaderboardV2VersionsLinkagesResponse`` - ``Components/Schemas/GameCenterLeaderboardV2VersionsLinkagesResponse``
@@ -1086,6 +1217,10 @@ Each resource type typically includes:
- ``Components/Schemas/GameCenterPlayerAchievementSubmission`` - ``Components/Schemas/GameCenterPlayerAchievementSubmission``
- ``Components/Schemas/GameCenterPlayerAchievementSubmissionCreateRequest`` - ``Components/Schemas/GameCenterPlayerAchievementSubmissionCreateRequest``
- ``Components/Schemas/GameCenterPlayerAchievementSubmissionResponse`` - ``Components/Schemas/GameCenterPlayerAchievementSubmissionResponse``
- ``Components/Schemas/GameCenterScoreModeration``
- ``Components/Schemas/GameCenterScoreModerationResponse``
- ``Components/Schemas/GameCenterScoreModerationUpdateRequest``
- ``Components/Schemas/GameCenterScoreModerationsResponse``
- ``Components/Schemas/GameCenterVersionState`` - ``Components/Schemas/GameCenterVersionState``
### Users and Roles ### Users and Roles
@@ -1270,14 +1405,17 @@ Each resource type typically includes:
- ``Components/Schemas/DiagnosticInsightType`` - ``Components/Schemas/DiagnosticInsightType``
- ``Components/Schemas/DiagnosticLog`` - ``Components/Schemas/DiagnosticLog``
- ``Components/Schemas/DiagnosticLogCallStackNode`` - ``Components/Schemas/DiagnosticLogCallStackNode``
- ``Components/Schemas/DiagnosticLogs``
- ``Components/Schemas/DiagnosticSignature`` - ``Components/Schemas/DiagnosticSignature``
- ``Components/Schemas/DiagnosticSignatureLogsLinkagesResponse`` - ``Components/Schemas/DiagnosticSignatureLogsLinkagesResponse``
- ``Components/Schemas/DiagnosticSignaturesResponse`` - ``Components/Schemas/DiagnosticSignaturesResponse``
- ``Components/Schemas/MetricCategory`` - ``Components/Schemas/MetricCategory``
- ``Components/Schemas/MetricsInsight`` - ``Components/Schemas/MetricsInsight``
- ``Components/Schemas/PerfPowerMetric`` - ``Components/Schemas/PerfPowerMetric``
- ``Components/Schemas/diagnosticLogs`` - ``Components/Schemas/PerformanceOverview``
- ``Components/Schemas/xcodeMetrics`` - ``Components/Schemas/PerformanceSignature``
- ``Components/Schemas/XcodeMetrics``
- ``Components/Schemas/XcodeOverview``
### Sandbox Testing ### Sandbox Testing
@@ -1410,6 +1548,7 @@ Each resource type typically includes:
- ``Components/Schemas/BrazilAgeRating`` - ``Components/Schemas/BrazilAgeRating``
- ``Components/Schemas/ChecksumAlgorithm`` - ``Components/Schemas/ChecksumAlgorithm``
- ``Components/Schemas/Checksums`` - ``Components/Schemas/Checksums``
- ``Components/Schemas/Csv``
- ``Components/Schemas/DeliveryFileUploadOperation`` - ``Components/Schemas/DeliveryFileUploadOperation``
- ``Components/Schemas/DocumentLinks`` - ``Components/Schemas/DocumentLinks``
- ``Components/Schemas/ErrorLinks`` - ``Components/Schemas/ErrorLinks``
@@ -1417,6 +1556,7 @@ Each resource type typically includes:
- ``Components/Schemas/ErrorSourceParameter`` - ``Components/Schemas/ErrorSourceParameter``
- ``Components/Schemas/ErrorSourcePointer`` - ``Components/Schemas/ErrorSourcePointer``
- ``Components/Schemas/FileLocation`` - ``Components/Schemas/FileLocation``
- ``Components/Schemas/Gzip``
- ``Components/Schemas/HttpHeader`` - ``Components/Schemas/HttpHeader``
- ``Components/Schemas/IconAssetType`` - ``Components/Schemas/IconAssetType``
- ``Components/Schemas/ImageAsset`` - ``Components/Schemas/ImageAsset``
@@ -1434,5 +1574,3 @@ Each resource type typically includes:
- ``Components/Schemas/StateDetail`` - ``Components/Schemas/StateDetail``
- ``Components/Schemas/StringToStringMap`` - ``Components/Schemas/StringToStringMap``
- ``Components/Schemas/UploadOperation`` - ``Components/Schemas/UploadOperation``
- ``Components/Schemas/csv``
- ``Components/Schemas/gzip``
@@ -1,18 +1,14 @@
# ``Operations`` # ``Operations``
API operations, with input and output types, generated from the paths section of the OpenAPI document. The request and response types of each API operation.
## Overview ## Overview
The ``Operations`` namespace contains a nested enum for each API operation defined in the App Store Connect API OpenAPI specification. Each operation enum encapsulates the `Input` and `Output` types for that specific endpoint. Each operation is an enum, named after its ``APIProtocol`` method, that contains:
Each operation typically provides: - `Input`: The request, split into `path`, `query`, `headers`, and `body` as the endpoint requires.
- `Output`: The response, with a case for each documented status, such as `ok`, and `undocumented(statusCode:_:)` for any other.
- An **`Input`** struct containing the request `Path`, `Query`, `Headers`, and `Body` types - `id`: The operation identifier in the OpenAPI document, such as `apps_getCollection`.
- An **`Output`** enum with cases for each possible HTTP response status code
- An **`id`** string constant with the operation identifier
These types are used by the ``APIProtocol`` methods and the ``Client`` implementation.
## Topics ## Topics
@@ -104,6 +100,9 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/AppsSubscriptionGracePeriodGetToOneRelated`` - ``Operations/AppsSubscriptionGracePeriodGetToOneRelated``
- ``Operations/AppsSubscriptionGroupsGetToManyRelated`` - ``Operations/AppsSubscriptionGroupsGetToManyRelated``
- ``Operations/AppsWebhooksGetToManyRelated`` - ``Operations/AppsWebhooksGetToManyRelated``
- ``Operations/AppsAssetLibraryGetToOneRelationship``
- ``Operations/AppsAssetLibraryGetToOneRelated``
- ``Operations/AppsPerformanceOverviewsGetToManyRelated``
- ``Operations/AppInfosGetInstance`` - ``Operations/AppInfosGetInstance``
- ``Operations/AppInfosUpdateInstance`` - ``Operations/AppInfosUpdateInstance``
- ``Operations/AppInfosAgeRatingDeclarationGetToOneRelated`` - ``Operations/AppInfosAgeRatingDeclarationGetToOneRelated``
@@ -205,6 +204,8 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/AppStoreVersionLocalizationsSearchKeywordsCreateToManyRelationship`` - ``Operations/AppStoreVersionLocalizationsSearchKeywordsCreateToManyRelationship``
- ``Operations/AppStoreVersionLocalizationsSearchKeywordsDeleteToManyRelationship`` - ``Operations/AppStoreVersionLocalizationsSearchKeywordsDeleteToManyRelationship``
- ``Operations/AppStoreVersionLocalizationsSearchKeywordsGetToManyRelated`` - ``Operations/AppStoreVersionLocalizationsSearchKeywordsGetToManyRelated``
- ``Operations/AppStoreVersionLocalizationsPlacementsGetToManyRelationship``
- ``Operations/AppStoreVersionLocalizationsPlacementsGetToManyRelated``
- ``Operations/AppStoreVersionPhasedReleasesCreateInstance`` - ``Operations/AppStoreVersionPhasedReleasesCreateInstance``
- ``Operations/AppStoreVersionPhasedReleasesUpdateInstance`` - ``Operations/AppStoreVersionPhasedReleasesUpdateInstance``
- ``Operations/AppStoreVersionPhasedReleasesDeleteInstance`` - ``Operations/AppStoreVersionPhasedReleasesDeleteInstance``
@@ -239,6 +240,8 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/AppStoreVersionExperimentTreatmentLocalizationsAppScreenshotSetsGetToManyRelated`` - ``Operations/AppStoreVersionExperimentTreatmentLocalizationsAppScreenshotSetsGetToManyRelated``
- ``Operations/AppStoreVersionExperimentTreatmentLocalizationsAppPreviewSetsGetToManyRelationship`` - ``Operations/AppStoreVersionExperimentTreatmentLocalizationsAppPreviewSetsGetToManyRelationship``
- ``Operations/AppStoreVersionExperimentTreatmentLocalizationsAppScreenshotSetsGetToManyRelationship`` - ``Operations/AppStoreVersionExperimentTreatmentLocalizationsAppScreenshotSetsGetToManyRelationship``
- ``Operations/AppStoreVersionExperimentTreatmentLocalizationsPlacementsGetToManyRelationship``
- ``Operations/AppStoreVersionExperimentTreatmentLocalizationsPlacementsGetToManyRelated``
### App Custom Product Pages ### App Custom Product Pages
@@ -265,6 +268,8 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/AppCustomProductPageLocalizationsSearchKeywordsCreateToManyRelationship`` - ``Operations/AppCustomProductPageLocalizationsSearchKeywordsCreateToManyRelationship``
- ``Operations/AppCustomProductPageLocalizationsSearchKeywordsDeleteToManyRelationship`` - ``Operations/AppCustomProductPageLocalizationsSearchKeywordsDeleteToManyRelationship``
- ``Operations/AppCustomProductPageLocalizationsSearchKeywordsGetToManyRelated`` - ``Operations/AppCustomProductPageLocalizationsSearchKeywordsGetToManyRelated``
- ``Operations/AppCustomProductPageLocalizationsPlacementsGetToManyRelationship``
- ``Operations/AppCustomProductPageLocalizationsPlacementsGetToManyRelated``
### App Clips ### App Clips
@@ -320,6 +325,8 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/AppEventLocalizationsAppEventVideoClipsGetToManyRelated`` - ``Operations/AppEventLocalizationsAppEventVideoClipsGetToManyRelated``
- ``Operations/AppEventLocalizationsAppEventScreenshotsGetToManyRelationship`` - ``Operations/AppEventLocalizationsAppEventScreenshotsGetToManyRelationship``
- ``Operations/AppEventLocalizationsAppEventVideoClipsGetToManyRelationship`` - ``Operations/AppEventLocalizationsAppEventVideoClipsGetToManyRelationship``
- ``Operations/AppEventLocalizationsPlacementsGetToManyRelationship``
- ``Operations/AppEventLocalizationsPlacementsGetToManyRelated``
- ``Operations/AppEventScreenshotsCreateInstance`` - ``Operations/AppEventScreenshotsCreateInstance``
- ``Operations/AppEventScreenshotsGetInstance`` - ``Operations/AppEventScreenshotsGetInstance``
- ``Operations/AppEventScreenshotsUpdateInstance`` - ``Operations/AppEventScreenshotsUpdateInstance``
@@ -356,6 +363,32 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/RoutingAppCoveragesUpdateInstance`` - ``Operations/RoutingAppCoveragesUpdateInstance``
- ``Operations/RoutingAppCoveragesDeleteInstance`` - ``Operations/RoutingAppCoveragesDeleteInstance``
### App Asset Library
- ``Operations/AppAssetLibrariesGetInstance``
- ``Operations/AppAssetLibrariesImagesGetToManyRelationship``
- ``Operations/AppAssetLibrariesImagesGetToManyRelated``
- ``Operations/AppAssetLibrariesVideosGetToManyRelationship``
- ``Operations/AppAssetLibrariesVideosGetToManyRelated``
- ``Operations/AppAssetLibraryImagesCreateInstance``
- ``Operations/AppAssetLibraryImagesGetInstance``
- ``Operations/AppAssetLibraryImagesUpdateInstance``
- ``Operations/AppAssetLibraryImagesDeleteInstance``
- ``Operations/AppAssetLibraryImagesPlacementsGetToManyRelationship``
- ``Operations/AppAssetLibraryImagesPlacementsGetToManyRelated``
- ``Operations/AppAssetLibraryVideosCreateInstance``
- ``Operations/AppAssetLibraryVideosGetInstance``
- ``Operations/AppAssetLibraryVideosUpdateInstance``
- ``Operations/AppAssetLibraryVideosDeleteInstance``
- ``Operations/AppAssetLibraryVideosPlacementsGetToManyRelationship``
- ``Operations/AppAssetLibraryVideosPlacementsGetToManyRelated``
- ``Operations/AppAssetLibraryPlacementsCreateInstance``
- ``Operations/AppAssetLibraryPlacementsGetInstance``
- ``Operations/AppAssetLibraryPlacementsDeleteInstance``
- ``Operations/AppAssetLibraryPlacementOrderingRequestsCreateInstance``
- ``Operations/AppAssetLibraryRefDataGetCollection``
- ``Operations/AppAssetLibraryRefDataGetInstance``
### App Encryption ### App Encryption
- ``Operations/AppEncryptionDeclarationsGetCollection`` - ``Operations/AppEncryptionDeclarationsGetCollection``
@@ -579,15 +612,33 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/InAppPurchasesV2OfferCodesGetToManyRelationship`` - ``Operations/InAppPurchasesV2OfferCodesGetToManyRelationship``
- ``Operations/InAppPurchasesV2PricePointsGetToManyRelationship`` - ``Operations/InAppPurchasesV2PricePointsGetToManyRelationship``
- ``Operations/InAppPurchasesV2PromotedPurchaseGetToOneRelationship`` - ``Operations/InAppPurchasesV2PromotedPurchaseGetToOneRelationship``
- ``Operations/InAppPurchasesV2VersionsGetToManyRelationship``
- ``Operations/InAppPurchasesV2VersionsGetToManyRelated``
- ``Operations/InAppPurchaseVersionsCreateInstance``
- ``Operations/InAppPurchaseVersionsGetInstance``
- ``Operations/InAppPurchaseVersionsImageGetToOneRelationship``
- ``Operations/InAppPurchaseVersionsImageGetToOneRelated``
- ``Operations/InAppPurchaseVersionsImagesGetToManyRelationship``
- ``Operations/InAppPurchaseVersionsImagesGetToManyRelated``
- ``Operations/InAppPurchaseVersionsLocalizationsGetToManyRelationship``
- ``Operations/InAppPurchaseVersionsLocalizationsGetToManyRelated``
- ``Operations/InAppPurchaseLocalizationsCreateInstance`` - ``Operations/InAppPurchaseLocalizationsCreateInstance``
- ``Operations/InAppPurchaseLocalizationsGetInstance`` - ``Operations/InAppPurchaseLocalizationsGetInstance``
- ``Operations/InAppPurchaseLocalizationsUpdateInstance`` - ``Operations/InAppPurchaseLocalizationsUpdateInstance``
- ``Operations/InAppPurchaseLocalizationsDeleteInstance`` - ``Operations/InAppPurchaseLocalizationsDeleteInstance``
- ``Operations/InAppPurchaseLocalizationsV2CreateInstance``
- ``Operations/InAppPurchaseLocalizationsV2GetInstance``
- ``Operations/InAppPurchaseLocalizationsV2UpdateInstance``
- ``Operations/InAppPurchaseLocalizationsV2DeleteInstance``
- ``Operations/InAppPurchaseContentsGetInstance`` - ``Operations/InAppPurchaseContentsGetInstance``
- ``Operations/InAppPurchaseImagesCreateInstance`` - ``Operations/InAppPurchaseImagesCreateInstance``
- ``Operations/InAppPurchaseImagesGetInstance`` - ``Operations/InAppPurchaseImagesGetInstance``
- ``Operations/InAppPurchaseImagesUpdateInstance`` - ``Operations/InAppPurchaseImagesUpdateInstance``
- ``Operations/InAppPurchaseImagesDeleteInstance`` - ``Operations/InAppPurchaseImagesDeleteInstance``
- ``Operations/InAppPurchaseImagesV2CreateInstance``
- ``Operations/InAppPurchaseImagesV2GetInstance``
- ``Operations/InAppPurchaseImagesV2UpdateInstance``
- ``Operations/InAppPurchaseImagesV2DeleteInstance``
- ``Operations/InAppPurchaseAppStoreReviewScreenshotsCreateInstance`` - ``Operations/InAppPurchaseAppStoreReviewScreenshotsCreateInstance``
- ``Operations/InAppPurchaseAppStoreReviewScreenshotsGetInstance`` - ``Operations/InAppPurchaseAppStoreReviewScreenshotsGetInstance``
- ``Operations/InAppPurchaseAppStoreReviewScreenshotsUpdateInstance`` - ``Operations/InAppPurchaseAppStoreReviewScreenshotsUpdateInstance``
@@ -658,6 +709,18 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/SubscriptionsSubscriptionAvailabilityGetToOneRelated`` - ``Operations/SubscriptionsSubscriptionAvailabilityGetToOneRelated``
- ``Operations/SubscriptionsSubscriptionLocalizationsGetToManyRelated`` - ``Operations/SubscriptionsSubscriptionLocalizationsGetToManyRelated``
- ``Operations/SubscriptionsWinBackOffersGetToManyRelated`` - ``Operations/SubscriptionsWinBackOffersGetToManyRelated``
- ``Operations/SubscriptionsPlanAvailabilitiesGetToManyRelationship``
- ``Operations/SubscriptionsPlanAvailabilitiesGetToManyRelated``
- ``Operations/SubscriptionsVersionsGetToManyRelationship``
- ``Operations/SubscriptionsVersionsGetToManyRelated``
- ``Operations/SubscriptionVersionsCreateInstance``
- ``Operations/SubscriptionVersionsGetInstance``
- ``Operations/SubscriptionVersionsImageGetToOneRelationship``
- ``Operations/SubscriptionVersionsImageGetToOneRelated``
- ``Operations/SubscriptionVersionsImagesGetToManyRelationship``
- ``Operations/SubscriptionVersionsImagesGetToManyRelated``
- ``Operations/SubscriptionVersionsLocalizationsGetToManyRelationship``
- ``Operations/SubscriptionVersionsLocalizationsGetToManyRelated``
- ``Operations/SubscriptionGroupsCreateInstance`` - ``Operations/SubscriptionGroupsCreateInstance``
- ``Operations/SubscriptionGroupsGetInstance`` - ``Operations/SubscriptionGroupsGetInstance``
- ``Operations/SubscriptionGroupsUpdateInstance`` - ``Operations/SubscriptionGroupsUpdateInstance``
@@ -666,19 +729,37 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/SubscriptionGroupsSubscriptionsGetToManyRelationship`` - ``Operations/SubscriptionGroupsSubscriptionsGetToManyRelationship``
- ``Operations/SubscriptionGroupsSubscriptionGroupLocalizationsGetToManyRelated`` - ``Operations/SubscriptionGroupsSubscriptionGroupLocalizationsGetToManyRelated``
- ``Operations/SubscriptionGroupsSubscriptionsGetToManyRelated`` - ``Operations/SubscriptionGroupsSubscriptionsGetToManyRelated``
- ``Operations/SubscriptionGroupsVersionsGetToManyRelationship``
- ``Operations/SubscriptionGroupsVersionsGetToManyRelated``
- ``Operations/SubscriptionGroupVersionsCreateInstance``
- ``Operations/SubscriptionGroupVersionsGetInstance``
- ``Operations/SubscriptionGroupVersionsLocalizationsGetToManyRelationship``
- ``Operations/SubscriptionGroupVersionsLocalizationsGetToManyRelated``
- ``Operations/SubscriptionGroupLocalizationsCreateInstance`` - ``Operations/SubscriptionGroupLocalizationsCreateInstance``
- ``Operations/SubscriptionGroupLocalizationsGetInstance`` - ``Operations/SubscriptionGroupLocalizationsGetInstance``
- ``Operations/SubscriptionGroupLocalizationsUpdateInstance`` - ``Operations/SubscriptionGroupLocalizationsUpdateInstance``
- ``Operations/SubscriptionGroupLocalizationsDeleteInstance`` - ``Operations/SubscriptionGroupLocalizationsDeleteInstance``
- ``Operations/SubscriptionGroupLocalizationsV2CreateInstance``
- ``Operations/SubscriptionGroupLocalizationsV2GetInstance``
- ``Operations/SubscriptionGroupLocalizationsV2UpdateInstance``
- ``Operations/SubscriptionGroupLocalizationsV2DeleteInstance``
- ``Operations/SubscriptionGroupSubmissionsCreateInstance`` - ``Operations/SubscriptionGroupSubmissionsCreateInstance``
- ``Operations/SubscriptionLocalizationsCreateInstance`` - ``Operations/SubscriptionLocalizationsCreateInstance``
- ``Operations/SubscriptionLocalizationsGetInstance`` - ``Operations/SubscriptionLocalizationsGetInstance``
- ``Operations/SubscriptionLocalizationsUpdateInstance`` - ``Operations/SubscriptionLocalizationsUpdateInstance``
- ``Operations/SubscriptionLocalizationsDeleteInstance`` - ``Operations/SubscriptionLocalizationsDeleteInstance``
- ``Operations/SubscriptionLocalizationsV2CreateInstance``
- ``Operations/SubscriptionLocalizationsV2GetInstance``
- ``Operations/SubscriptionLocalizationsV2UpdateInstance``
- ``Operations/SubscriptionLocalizationsV2DeleteInstance``
- ``Operations/SubscriptionImagesCreateInstance`` - ``Operations/SubscriptionImagesCreateInstance``
- ``Operations/SubscriptionImagesGetInstance`` - ``Operations/SubscriptionImagesGetInstance``
- ``Operations/SubscriptionImagesUpdateInstance`` - ``Operations/SubscriptionImagesUpdateInstance``
- ``Operations/SubscriptionImagesDeleteInstance`` - ``Operations/SubscriptionImagesDeleteInstance``
- ``Operations/SubscriptionImagesV2CreateInstance``
- ``Operations/SubscriptionImagesV2GetInstance``
- ``Operations/SubscriptionImagesV2UpdateInstance``
- ``Operations/SubscriptionImagesV2DeleteInstance``
- ``Operations/SubscriptionAppStoreReviewScreenshotsCreateInstance`` - ``Operations/SubscriptionAppStoreReviewScreenshotsCreateInstance``
- ``Operations/SubscriptionAppStoreReviewScreenshotsGetInstance`` - ``Operations/SubscriptionAppStoreReviewScreenshotsGetInstance``
- ``Operations/SubscriptionAppStoreReviewScreenshotsUpdateInstance`` - ``Operations/SubscriptionAppStoreReviewScreenshotsUpdateInstance``
@@ -687,6 +768,12 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/SubscriptionAvailabilitiesGetInstance`` - ``Operations/SubscriptionAvailabilitiesGetInstance``
- ``Operations/SubscriptionAvailabilitiesAvailableTerritoriesGetToManyRelated`` - ``Operations/SubscriptionAvailabilitiesAvailableTerritoriesGetToManyRelated``
- ``Operations/SubscriptionAvailabilitiesAvailableTerritoriesGetToManyRelationship`` - ``Operations/SubscriptionAvailabilitiesAvailableTerritoriesGetToManyRelationship``
- ``Operations/SubscriptionPlanAvailabilitiesCreateInstance``
- ``Operations/SubscriptionPlanAvailabilitiesGetInstance``
- ``Operations/SubscriptionPlanAvailabilitiesUpdateInstance``
- ``Operations/SubscriptionPlanAvailabilitiesAvailableTerritoriesGetToManyRelationship``
- ``Operations/SubscriptionPlanAvailabilitiesAvailableTerritoriesReplaceToManyRelationship``
- ``Operations/SubscriptionPlanAvailabilitiesAvailableTerritoriesGetToManyRelated``
- ``Operations/SubscriptionGracePeriodsGetInstance`` - ``Operations/SubscriptionGracePeriodsGetInstance``
- ``Operations/SubscriptionGracePeriodsUpdateInstance`` - ``Operations/SubscriptionGracePeriodsUpdateInstance``
- ``Operations/SubscriptionIntroductoryOffersCreateInstance`` - ``Operations/SubscriptionIntroductoryOffersCreateInstance``
@@ -711,6 +798,7 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/SubscriptionPricePointsGetInstance`` - ``Operations/SubscriptionPricePointsGetInstance``
- ``Operations/SubscriptionPricePointsEqualizationsGetToManyRelated`` - ``Operations/SubscriptionPricePointsEqualizationsGetToManyRelated``
- ``Operations/SubscriptionPricePointsEqualizationsGetToManyRelationship`` - ``Operations/SubscriptionPricePointsEqualizationsGetToManyRelationship``
- ``Operations/SubscriptionPricePointsAdjustedEqualizationsGetToManyRelated``
- ``Operations/SubscriptionPricesCreateInstance`` - ``Operations/SubscriptionPricesCreateInstance``
- ``Operations/SubscriptionPricesDeleteInstance`` - ``Operations/SubscriptionPricesDeleteInstance``
- ``Operations/SubscriptionPromotionalOffersCreateInstance`` - ``Operations/SubscriptionPromotionalOffersCreateInstance``
@@ -771,6 +859,9 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/GameCenterDetailsGameCenterLeaderboardsV2ReplaceToManyRelationship`` - ``Operations/GameCenterDetailsGameCenterLeaderboardsV2ReplaceToManyRelationship``
- ``Operations/GameCenterDetailsLeaderboardReleasesGetToManyRelationship`` - ``Operations/GameCenterDetailsLeaderboardReleasesGetToManyRelationship``
- ``Operations/GameCenterDetailsLeaderboardSetReleasesGetToManyRelationship`` - ``Operations/GameCenterDetailsLeaderboardSetReleasesGetToManyRelationship``
- ``Operations/GameCenterDetailsBlockedPlayersGetToManyRelationship``
- ``Operations/GameCenterDetailsBlockedPlayersGetToManyRelated``
- ``Operations/GameCenterDetailPlayersUpdateInstance``
- ``Operations/GameCenterGroupsGetCollection`` - ``Operations/GameCenterGroupsGetCollection``
- ``Operations/GameCenterGroupsCreateInstance`` - ``Operations/GameCenterGroupsCreateInstance``
- ``Operations/GameCenterGroupsGetInstance`` - ``Operations/GameCenterGroupsGetInstance``
@@ -869,6 +960,9 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/GameCenterLeaderboardsV2ChallengeUpdateToOneRelationship`` - ``Operations/GameCenterLeaderboardsV2ChallengeUpdateToOneRelationship``
- ``Operations/GameCenterLeaderboardsV2VersionsGetToManyRelationship`` - ``Operations/GameCenterLeaderboardsV2VersionsGetToManyRelationship``
- ``Operations/GameCenterLeaderboardsV2VersionsGetToManyRelated`` - ``Operations/GameCenterLeaderboardsV2VersionsGetToManyRelated``
- ``Operations/GameCenterLeaderboardsV2GameCenterScoreModerationsGetToManyRelationship``
- ``Operations/GameCenterLeaderboardsV2GameCenterScoreModerationsGetToManyRelated``
- ``Operations/GameCenterScoreModerationsUpdateInstance``
- ``Operations/GameCenterLeaderboardVersionsV2CreateInstance`` - ``Operations/GameCenterLeaderboardVersionsV2CreateInstance``
- ``Operations/GameCenterLeaderboardVersionsV2GetInstance`` - ``Operations/GameCenterLeaderboardVersionsV2GetInstance``
- ``Operations/GameCenterLeaderboardVersionsV2LocalizationsGetToManyRelated`` - ``Operations/GameCenterLeaderboardVersionsV2LocalizationsGetToManyRelated``
@@ -1,18 +1,15 @@
# ``Servers`` # ``Servers``
Server URLs defined in the OpenAPI document. The App Store Connect API server URLs.
## Overview ## Overview
The ``Servers`` namespace provides access to the base URLs defined in the App Store Connect API OpenAPI specification. Use these URLs when creating a ``Client`` instance. The specification defines a single server, `https://api.appstoreconnect.apple.com/`. Pass its URL to ``Client``:
```swift ```swift
let client = Client( let client = Client(
serverURL: try Servers.Server1.url(), serverURL: try Servers.Server1.url(),
transport: URLSessionTransport(), transport: URLSessionTransport()
middlewares: [
BearerAuthMiddleware(token: yourJWTToken)
]
) )
``` ```
@@ -21,4 +18,7 @@ let client = Client(
### Server URLs ### Server URLs
- ``Servers/Server1`` - ``Servers/Server1``
### Deprecated
- ``Servers/server1()`` - ``Servers/server1()``
@@ -1,36 +1,78 @@
# ``ASConnectService`` # ``ASConnectService``
A Swift client library for the App Store Connect API, generated from the official OpenAPI specification. A type-safe Swift client for the App Store Connect API.
## Overview ## 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. 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).
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.
### Creating a Client ### 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). 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 ```swift
import ASConnectService import ASConnectService
import OpenAPIURLSession import OpenAPIURLSession
let tokenProvider = try APIKeyTokenProvider(
issuerID: yourIssuerID,
keyID: yourKeyID,
privateKey: yourP8FileContents
)
let client = Client( let client = Client(
serverURL: try Servers.server1(), serverURL: try Servers.Server1.url(),
transport: URLSessionTransport(), transport: URLSessionTransport(),
middlewares: [ middlewares: [
BearerAuthMiddleware(token: yourJWTToken) BearerAuthMiddleware { try await tokenProvider.token() }
] ]
) )
``` ```
### Making API Calls To use a token you signed yourself, pass it directly. It expires after 20 minutes at most:
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.
```swift ```swift
let response = try await client.appsGetCollection(.init()) BearerAuthMiddleware(token: yourJWTToken)
```
### Making API Calls
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 ``Components/Schemas/PagedDocumentLinks/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() }
]
``` ```
## Topics ## Topics
@@ -43,6 +85,15 @@ let response = try await client.appsGetCollection(.init())
### Authentication ### Authentication
- ``BearerAuthMiddleware`` - ``BearerAuthMiddleware``
- ``APIKeyTokenProvider``
### Pagination
- ``PagedSequence``
### Rate Limiting
- ``RateLimitMiddleware``
### Generated Types ### Generated Types
@@ -0,0 +1,33 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
import struct Foundation.URLComponents
extension Components.Schemas.PagedDocumentLinks {
// MARK: Properties
/// The cursor of the next page, or `nil` on the last page.
///
/// Pass it as the `cursor` query parameter of the same operation to fetch the next page.
public var nextCursor: String? {
guard let next else {
return nil
}
return URLComponents(string: next)?
.queryItems?
.first { $0.name == "cursor" }?
.value
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -13,38 +13,56 @@
// ===----------------------------------------------------------------------=== // ===----------------------------------------------------------------------===
import struct Foundation.URL import struct Foundation.URL
import struct Foundation.URLComponents
import struct Foundation.URLQueryItem
import struct HTTPTypes.HTTPField
import struct HTTPTypes.HTTPFields
import struct HTTPTypes.HTTPRequest import struct HTTPTypes.HTTPRequest
import struct HTTPTypes.HTTPResponse import struct HTTPTypes.HTTPResponse
import protocol OpenAPIRuntime.ClientMiddleware import protocol OpenAPIRuntime.ClientMiddleware
import class OpenAPIRuntime.HTTPBody import class OpenAPIRuntime.HTTPBody
/// A client middleware that injects a Bearer authentication token into outgoing HTTP requests. /// A client middleware that authenticates requests with a Bearer token.
/// ///
/// This middleware appends an `Authorization` header with a Bearer token to every request /// This middleware sets the `Authorization` header of every request to `Bearer <token>`, as the
/// before forwarding it to the next handler in the middleware chain. It is intended for use /// App Store Connect API requires JSON Web Token (JWT) authentication.
/// with the App Store Connect API, which requires JSON Web Token (JWT) authentication.
/// ///
/// ## Usage /// ## Usage
/// ///
/// Provide a fixed token:
///
/// ```swift /// ```swift
/// let middleware = BearerAuthMiddleware(token: "your-jwt-token") /// let middleware = BearerAuthMiddleware(token: "your-jwt-token")
/// ``` /// ```
///
/// Tokens expire after 20 minutes at most, so long-lived clients should provide a token provider, such as
/// ``APIKeyTokenProvider``:
///
/// ```swift
/// let middleware = BearerAuthMiddleware {
/// try await tokenProvider.token()
/// }
/// ```
public struct BearerAuthMiddleware { public struct BearerAuthMiddleware {
// MARK: Properties // MARK: Properties
/// The Bearer token to include in the `Authorization` header of each request. /// The closure that provides the Bearer token for each request.
private let token: String private let tokenProvider: @Sendable () async throws -> String
// MARK: Initializers // MARK: Initializers
/// Creates a new middleware instance with the given Bearer token. /// Creates a new middleware instance with a fixed Bearer token.
/// - Parameter token: A JSON Web Token (JWT) string used to authenticate requests to the App Store Connect API. /// - Parameter token: A JSON Web Token (JWT) used to authenticate requests to the App Store Connect API.
init(token: String) { public init(
self.token = token token: String
) {
self.init { token }
}
/// Creates a new middleware instance that asks for a Bearer token on every request.
///
/// If the provider throws, the error is rethrown and the request is not sent.
/// - Parameter tokenProvider: A closure that returns a valid JSON Web Token (JWT).
public init(
tokenProvider: @escaping @Sendable () async throws -> String
) {
self.tokenProvider = tokenProvider
} }
} }
@@ -68,6 +86,8 @@ extension BearerAuthMiddleware: ClientMiddleware {
operationID: String, operationID: String,
next: @Sendable (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?) next: @Sendable (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?)
) async throws -> (HTTPResponse, HTTPBody?) { ) async throws -> (HTTPResponse, HTTPBody?) {
let token = try await tokenProvider()
var request = request var request = request
request.headerFields[.authorization] = "Bearer \(token)" request.headerFields[.authorization] = "Bearer \(token)"
@@ -0,0 +1,149 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
import struct Foundation.URL
import typealias Foundation.TimeInterval
import struct HTTPTypes.HTTPRequest
import struct HTTPTypes.HTTPResponse
import protocol OpenAPIRuntime.ClientMiddleware
import class OpenAPIRuntime.HTTPBody
/// A client middleware that retries rate-limited requests.
///
/// On a `429 Too Many Requests` response, it waits for the `Retry-After` seconds, or a delay that doubles from
/// `baseDelay`, and retries. It returns the `429` response instead when the retries run out, the delay exceeds
/// `maximumDelay`, or the request body can only be sent once.
///
/// ## Usage
///
/// Place it before ``BearerAuthMiddleware``, so retries get a fresh token:
///
/// ```swift
/// middlewares: [
/// RateLimitMiddleware(),
/// BearerAuthMiddleware { try await tokenProvider.token() }
/// ]
/// ```
public struct RateLimitMiddleware {
// MARK: Properties
/// The maximum number of times a request is retried.
private let maximumRetries: Int
/// The delay before the first retry, when the response has no `Retry-After` header.
private let baseDelay: TimeInterval
/// The longest delay to wait before a retry.
private let maximumDelay: TimeInterval
/// The closure that waits for a given number of seconds.
private let sleep: @Sendable (TimeInterval) async throws -> Void
// MARK: Initializers
/// Creates a new middleware instance.
/// - Parameters:
/// - maximumRetries: The maximum number of times a request is retried.
/// - baseDelay: The delay, in seconds, before the first retry when the response has no `Retry-After` header.
/// - maximumDelay: The longest delay, in seconds, to wait before a retry.
public init(
maximumRetries: Int = 3,
baseDelay: TimeInterval = 1,
maximumDelay: TimeInterval = 60
) {
self.init(
maximumRetries: maximumRetries,
baseDelay: baseDelay,
maximumDelay: maximumDelay,
sleep: { try await Task.sleep(nanoseconds: UInt64($0 * 1_000_000_000)) }
)
}
/// Creates a new middleware instance that waits with `sleep`, for testing.
package init(
maximumRetries: Int,
baseDelay: TimeInterval,
maximumDelay: TimeInterval,
sleep: @escaping @Sendable (TimeInterval) async throws -> Void
) {
self.maximumRetries = maximumRetries
self.baseDelay = baseDelay
self.maximumDelay = maximumDelay
self.sleep = sleep
}
}
// MARK: - ClientMiddleware
extension RateLimitMiddleware: ClientMiddleware {
// MARK: Methods
/// Sends an HTTP request, and retries it while its response is `429 Too Many Requests`.
/// - Parameters:
/// - request: The original HTTP request.
/// - body: The optional body of the request.
/// - baseURL: The base URL for the request.
/// - operationID: The identifier of the API operation being performed.
/// - next: The next handler in the middleware chain.
/// - Returns: The HTTP response and optional body returned by the next handler.
/// - Throws: An error if the next handler throws, or the task is cancelled while waiting.
public func intercept(
_ request: HTTPRequest,
body: HTTPBody?,
baseURL: URL,
operationID: String,
next: @Sendable (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?)
) async throws -> (HTTPResponse, HTTPBody?) {
var retries = 0
var backoff = baseDelay
while true {
let (response, responseBody) = try await next(
request,
body,
baseURL
)
guard
response.status == .tooManyRequests,
retries < maximumRetries,
body?.iterationBehavior != .single
else {
return (response, responseBody)
}
let delay = response.retryAfter ?? backoff
guard delay <= maximumDelay else {
return (response, responseBody)
}
try await sleep(delay)
retries += 1
backoff *= 2
}
}
}
// MARK: - HTTPResponse+RetryAfter
private extension HTTPResponse {
/// The seconds in the `Retry-After` header, if any, and never negative.
var retryAfter: TimeInterval? {
headerFields[.retryAfter]
.flatMap { TimeInterval($0) }
.map { max($0, 0) }
}
}
@@ -0,0 +1,189 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
#if canImport(CryptoKit)
import enum CryptoKit.P256
import struct Foundation.Data
import struct Foundation.Date
import class Foundation.JSONEncoder
import typealias Foundation.TimeInterval
/// A token provider that signs App Store Connect API tokens with an API key.
///
/// Each JSON Web Token (JWT) is reused until a minute before it expires:
///
/// ```swift
/// let tokenProvider = try APIKeyTokenProvider(
/// issuerID: "57246542-96fe-1a63-e053-0824d011072a",
/// keyID: "2X9R4HXF34",
/// privateKey: privateKey
/// )
///
/// let middleware = BearerAuthMiddleware {
/// try await tokenProvider.token()
/// }
/// ```
public actor APIKeyTokenProvider {
// MARK: Properties
/// The issuer ID of a team key, or `nil` for an individual key.
private let issuerID: String?
/// The ID of the API key.
private let keyID: String
/// The private key that signs the tokens.
private let privateKey: P256.Signing.PrivateKey
/// The closure that provides the current date.
private let now: @Sendable () -> Date
/// The last signed token, and its expiration date.
private var current: (token: String, expiresAt: Date)?
// MARK: Initializers
/// Creates a token provider with an App Store Connect API key.
/// - Parameters:
/// - issuerID: The issuer ID of a team key, or `nil` for an individual key.
/// - keyID: The ID of the key.
/// - privateKey: The contents of the key's `.p8` file.
/// - Throws: An error if `privateKey` is not a P-256 private key in PEM format.
public init(
issuerID: String?,
keyID: String,
privateKey: String
) throws {
try self.init(
issuerID: issuerID,
keyID: keyID,
privateKey: privateKey,
now: { Date() }
)
}
/// Creates a token provider that reads the current date from `now`, for testing.
package init(
issuerID: String?,
keyID: String,
privateKey: String,
now: @escaping @Sendable () -> Date
) throws {
self.issuerID = issuerID
self.keyID = keyID
self.privateKey = try P256.Signing.PrivateKey(pemRepresentation: privateKey)
self.now = now
}
// MARK: Methods
/// Returns the current token, or signs a new one if it expires within a minute.
/// - Returns: A JSON Web Token (JWT) valid for 20 minutes at most.
/// - Throws: An error if the token cannot be signed.
public func token() throws -> String {
let date = now()
if let current, current.expiresAt.timeIntervalSince(date) > .refreshMargin {
return current.token
}
let expiresAt = date.addingTimeInterval(.lifetime)
let token = try sign(
issuedAt: date,
expiresAt: expiresAt
)
current = (token, expiresAt)
return token
}
}
// MARK: - Helpers
extension APIKeyTokenProvider {
// MARK: Functions
/// Signs a new token.
/// - Parameters:
/// - issuedAt: The date the token is issued at.
/// - expiresAt: The date the token expires at.
/// - Returns: A JSON Web Token (JWT) signed with the ES256 algorithm.
/// - Throws: An error if the token cannot be encoded or signed.
private func sign(
issuedAt: Date,
expiresAt: Date
) throws -> String {
let encoder = JSONEncoder()
encoder.outputFormatting = .sortedKeys
let header = try encoder.encode(Header(kid: keyID))
let payload = try encoder.encode(
Payload(
iss: issuerID,
sub: issuerID == nil ? "user" : nil,
iat: Int(issuedAt.timeIntervalSince1970),
exp: Int(expiresAt.timeIntervalSince1970)
)
)
let message = "\(header.base64URLEncoded).\(payload.base64URLEncoded)"
let signature = try privateKey.signature(for: Data(message.utf8))
return "\(message).\(signature.rawRepresentation.base64URLEncoded)"
}
}
// MARK: - Header
/// The header of a token.
private struct Header: Encodable {
let alg = "ES256"
let kid: String
let typ = "JWT"
}
// MARK: - Payload
/// The payload of a token.
private struct Payload: Encodable {
let iss: String?
let sub: String?
let iat: Int
let exp: Int
let aud = "appstoreconnect-v1"
}
// MARK: - Data+Base64URL
private extension Data {
/// The Base64URL encoding of the data, without padding.
var base64URLEncoded: String {
base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
}
}
// MARK: - TimeInterval+Constants
private extension TimeInterval {
/// The lifetime of a token, which App Store Connect limits to 20 minutes.
static let lifetime: TimeInterval = 20 * 60
/// The time before the expiration of a token when a new one is signed.
static let refreshMargin: TimeInterval = 60
}
#endif
@@ -0,0 +1,117 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
/// An asynchronous sequence of the pages of a paged operation.
///
/// Each iteration fetches the next page, until a page has no next link:
///
/// ```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
/// }
/// ```
public struct PagedSequence<Page: Sendable>: AsyncSequence, Sendable {
// MARK: Type aliases
public typealias Element = Page
// MARK: Properties
/// The closure that returns the links of a page.
private let links: @Sendable (Page) -> Components.Schemas.PagedDocumentLinks
/// The closure that fetches the page at a cursor.
private let fetch: @Sendable (String?) async throws -> Page
// MARK: Initializers
/// Creates a sequence of the pages of a paged operation.
/// - Parameters:
/// - links: A closure that returns the links of a page.
/// - fetch: A closure that fetches the page at a cursor, or the first page if the cursor is `nil`.
public init(
links: @escaping @Sendable (Page) -> Components.Schemas.PagedDocumentLinks,
fetch: @escaping @Sendable (_ cursor: String?) async throws -> Page
) {
self.links = links
self.fetch = fetch
}
// MARK: Functions
public func makeAsyncIterator() -> Iterator {
Iterator(
links: links,
fetch: fetch
)
}
}
// MARK: - Iterator
extension PagedSequence {
/// An iterator that fetches one page at a time.
public struct Iterator: AsyncIteratorProtocol {
// MARK: Properties
/// The closure that returns the links of a page.
private let links: @Sendable (Page) -> Components.Schemas.PagedDocumentLinks
/// The closure that fetches the page at a cursor.
private let fetch: @Sendable (String?) async throws -> Page
/// The cursor of the next page, or `nil` for the first page.
private var cursor: String?
/// A Boolean value that indicates whether there are no more pages to fetch.
private var isFinished = false
// MARK: Initializers
init(
links: @escaping @Sendable (Page) -> Components.Schemas.PagedDocumentLinks,
fetch: @escaping @Sendable (String?) async throws -> Page
) {
self.links = links
self.fetch = fetch
}
// MARK: Functions
/// Fetches the next page.
/// - Returns: The next page, or `nil` after the last page.
/// - Throws: The error thrown by the fetch closure, after which the iterator returns `nil`.
public mutating func next() async throws -> Page? {
guard !isFinished else {
return nil
}
// Finishes the iteration if fetching the page throws.
isFinished = true
let page = try await fetch(cursor)
cursor = links(page).nextCursor
isFinished = cursor == nil
return page
}
}
}
@@ -17,3 +17,6 @@ generate:
- client - client
namingStrategy: idiomatic namingStrategy: idiomatic
accessModifier: public accessModifier: public
# Stops swift-format from reformatting the generated code.
additionalFileComments:
- swift-format-ignore-file
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,65 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
import Testing
// A non-testable import ensures that the extension can be used from outside the module.
import ASConnectService
@Suite("PagedDocumentLinks")
struct PagedDocumentLinksTests {
// MARK: Tests
@Test("Returns the cursor from the next link")
func returnsNextCursor() {
let links = Components.Schemas.PagedDocumentLinks(
_self: .Link.current,
next: "https://api.appstoreconnect.apple.com/v1/apps?cursor=Mg.ANmP3sY&limit=2"
)
#expect(links.nextCursor == "Mg.ANmP3sY")
}
@Test("Returns nil when there is no next link")
func returnsNilWithoutNextLink() {
let links = Components.Schemas.PagedDocumentLinks(_self: .Link.current)
#expect(links.nextCursor == nil)
}
@Test("Returns nil when the next link has no cursor")
func returnsNilWithoutCursor() {
let links = Components.Schemas.PagedDocumentLinks(
_self: .Link.current,
next: "https://api.appstoreconnect.apple.com/v1/apps?limit=2"
)
#expect(links.nextCursor == nil)
}
@Test("Passes the cursor to the query of a paged operation")
func passesCursorToQuery() {
let query = Operations.AppsGetCollection.Input.Query(limit: 2, cursor: "Mg.ANmP3sY")
#expect(query.cursor == "Mg.ANmP3sY")
}
}
// MARK: - String+Samples
private extension String {
enum Link {
static let current: String = "https://api.appstoreconnect.apple.com/v1/apps?limit=2"
}
}
@@ -1,9 +1,24 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
import Foundation import Foundation
import HTTPTypes import HTTPTypes
import OpenAPIRuntime import OpenAPIRuntime
import Testing import Testing
@testable import ASConnectService // A non-testable import ensures that the middleware can be created from outside the module.
import ASConnectService
@Suite("BearerAuthMiddleware") @Suite("BearerAuthMiddleware")
struct BearerAuthMiddlewareTests { struct BearerAuthMiddlewareTests {
@@ -32,17 +47,14 @@ struct BearerAuthMiddlewareTests {
let middleware = BearerAuthMiddleware(token: .Token.jwt) let middleware = BearerAuthMiddleware(token: .Token.jwt)
let requestBody: HTTPBody = HTTPBody("request-body") let requestBody: HTTPBody = HTTPBody("request-body")
var receivedBody: HTTPBody? // The next handler echoes the body back, so the test can read it.
let (_, receivedBody) = try await middleware.intercept(
_ = try await middleware.intercept(
.get, .get,
body: requestBody, body: requestBody,
baseURL: .base, baseURL: .base,
operationID: "createApp", operationID: "createApp",
next: { _, body, _ in next: { _, body, _ in
receivedBody = body (HTTPResponse(status: .created), body)
return (HTTPResponse(status: .created), nil)
} }
) )
@@ -112,6 +124,67 @@ struct BearerAuthMiddlewareTests {
} }
) )
} }
@Test("Asks the token provider for a token on every request")
func asksTokenProviderOnEveryRequest() async throws {
let tokens = TokenSequence()
let middleware = BearerAuthMiddleware {
await tokens.next()
}
for expectedToken in ["token-1", "token-2"] {
_ = try await middleware.intercept(
.get,
body: nil,
baseURL: .base,
operationID: "listApps",
next: { interceptedRequest, _, _ in
#expect(interceptedRequest.headerFields[.authorization] == "Bearer \(expectedToken)")
return (HTTPResponse(status: .ok), nil)
}
)
}
}
@Test("Rethrows the token provider error without calling the next handler")
func rethrowsTokenProviderError() async throws {
let middleware = BearerAuthMiddleware {
throw TokenError.expired
}
await #expect(throws: TokenError.expired) {
_ = try await middleware.intercept(
.get,
body: nil,
baseURL: .base,
operationID: "listApps",
next: { _, _, _ in
Issue.record("The next handler should not be called when the token provider throws")
return (HTTPResponse(status: .ok), nil)
}
)
}
}
}
// MARK: - Helpers
/// An actor that returns a new token every time it is asked for one.
private actor TokenSequence {
private var count = 0
func next() -> String {
count += 1
return "token-\(count)"
}
}
/// An error thrown by a token provider.
private enum TokenError: Error {
case expired
} }
// MARK: - HTTPRequest+Samples // MARK: - HTTPRequest+Samples
@@ -0,0 +1,165 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
import Foundation
import HTTPTypes
import OpenAPIRuntime
import Testing
// A non-testable import ensures that the middleware can be created from outside the module.
import ASConnectService
@Suite("RateLimitMiddleware")
struct RateLimitMiddlewareTests {
// MARK: Properties
private let recorder = Recorder()
// MARK: Tests
@Test("Returns a response that is not rate limited without retrying")
func returnsResponseWithoutRetrying() async throws {
let response = try await intercept(responses: [.ok])
#expect(response.status == .ok)
#expect(await recorder.calls == 1)
#expect(await recorder.delays.isEmpty)
}
@Test("Retries rate-limited requests with an exponential backoff")
func retriesWithBackoff() async throws {
let response = try await intercept(responses: [.tooManyRequests, .tooManyRequests, .ok])
#expect(response.status == .ok)
#expect(await recorder.calls == 3)
#expect(await recorder.delays == [1, 2])
}
@Test("Waits for the seconds in the Retry-After header")
func waitsForRetryAfter() async throws {
let response = try await intercept(responses: [.tooManyRequests(retryAfter: "5"), .ok])
#expect(response.status == .ok)
#expect(await recorder.delays == [5])
}
@Test("Returns the rate-limited response when the retries run out")
func returnsResponseWhenRetriesRunOut() async throws {
let response = try await intercept(
responses: [.tooManyRequests, .tooManyRequests, .tooManyRequests],
maximumRetries: 2
)
#expect(response.status == .tooManyRequests)
#expect(await recorder.calls == 3)
#expect(await recorder.delays == [1, 2])
}
@Test("Returns the rate-limited response when the delay exceeds the maximum")
func returnsResponseWhenDelayExceedsMaximum() async throws {
let response = try await intercept(responses: [.tooManyRequests(retryAfter: "3600"), .ok])
#expect(response.status == .tooManyRequests)
#expect(await recorder.calls == 1)
#expect(await recorder.delays.isEmpty)
}
@Test("Does not retry a request whose body can only be sent once")
func doesNotRetrySingleIterationBody() async throws {
let body = HTTPBody(
AsyncStream<HTTPBody.ByteChunk> { $0.finish() },
length: .unknown,
iterationBehavior: .single
)
let response = try await intercept(responses: [.tooManyRequests, .ok], body: body)
#expect(response.status == .tooManyRequests)
#expect(await recorder.calls == 1)
}
}
// MARK: - Helpers
private extension RateLimitMiddlewareTests {
func intercept(
responses: [HTTPResponse],
body: HTTPBody? = nil,
maximumRetries: Int = 3
) async throws -> HTTPResponse {
let recorder = recorder
let middleware = RateLimitMiddleware(
maximumRetries: maximumRetries,
baseDelay: 1,
maximumDelay: 60,
sleep: { await recorder.record(delay: $0) }
)
let (response, _) = try await middleware.intercept(
.get,
body: body,
baseURL: .base,
operationID: "apps_getCollection",
next: { _, _, _ in
(await recorder.response(from: responses), nil)
}
)
return response
}
}
/// An actor that records the calls to the next handler, and the delays the middleware waits for.
private actor Recorder {
private(set) var calls = 0
private(set) var delays: [TimeInterval] = []
func response(from responses: [HTTPResponse]) -> HTTPResponse {
defer { calls += 1 }
return responses[calls]
}
func record(delay: TimeInterval) {
delays.append(delay)
}
}
// MARK: - HTTPRequest+Samples
private extension HTTPRequest {
static let get = HTTPRequest(
method: .get,
scheme: "https",
authority: "api.appstoreconnect.apple.com",
path: "/v1/apps"
)
}
// MARK: - HTTPResponse+Samples
private extension HTTPResponse {
static let ok = HTTPResponse(status: .ok)
static let tooManyRequests = HTTPResponse(status: .tooManyRequests)
static func tooManyRequests(retryAfter: String) -> HTTPResponse {
HTTPResponse(status: .tooManyRequests, headerFields: [.retryAfter: retryAfter])
}
}
// MARK: - URL+Samples
private extension URL {
static let base = URL(string: "https://api.appstoreconnect.apple.com")!
}
@@ -0,0 +1,151 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
#if canImport(CryptoKit)
import CryptoKit
import Foundation
import Testing
// A non-testable import ensures that the provider can be created from outside the module.
import ASConnectService
@Suite("APIKeyTokenProvider")
struct APIKeyTokenProviderTests {
// MARK: Properties
private let key = P256.Signing.PrivateKey()
private let clock = TestClock()
// MARK: Tests
@Test("Signs a token for a team key")
func signsTeamKeyToken() async throws {
let token = try await makeProvider(issuerID: .Sample.issuerID).token()
let (header, payload) = try decode(token)
#expect(header == ["alg": "ES256", "kid": String.Sample.keyID, "typ": "JWT"])
#expect(payload["iss"] as? String == .Sample.issuerID)
#expect(payload["sub"] == nil)
#expect(payload["aud"] as? String == "appstoreconnect-v1")
#expect(payload["iat"] as? Int == Int(clock.date.timeIntervalSince1970))
#expect(payload["exp"] as? Int == Int(clock.date.timeIntervalSince1970) + 20 * 60)
}
@Test("Signs a token for an individual key")
func signsIndividualKeyToken() async throws {
let token = try await makeProvider(issuerID: nil).token()
let (_, payload) = try decode(token)
#expect(payload["iss"] == nil)
#expect(payload["sub"] as? String == "user")
}
@Test("Signs the token with the private key")
func signsWithPrivateKey() async throws {
let token = try await makeProvider(issuerID: .Sample.issuerID).token()
let parts = token.split(separator: ".").map(String.init)
let signature = try P256.Signing.ECDSASignature(rawRepresentation: try #require(Data(base64URL: parts[2])))
#expect(key.publicKey.isValidSignature(signature, for: Data("\(parts[0]).\(parts[1])".utf8)))
}
@Test("Returns the current token until it is about to expire")
func returnsCurrentToken() async throws {
let provider = try makeProvider(issuerID: .Sample.issuerID)
let token = try await provider.token()
clock.advance(by: 18 * 60)
#expect(try await provider.token() == token)
}
@Test("Signs a new token when the current one is about to expire")
func signsNewToken() async throws {
let provider = try makeProvider(issuerID: .Sample.issuerID)
let token = try await provider.token()
clock.advance(by: 19 * 60 + 1)
#expect(try await provider.token() != token)
}
@Test("Throws when the private key is not valid")
func throwsWithInvalidPrivateKey() {
#expect(throws: (any Error).self) {
try APIKeyTokenProvider(
issuerID: .Sample.issuerID,
keyID: .Sample.keyID,
privateKey: "not-a-private-key"
)
}
}
}
// MARK: - Helpers
private extension APIKeyTokenProviderTests {
func makeProvider(issuerID: String?) throws -> APIKeyTokenProvider {
try APIKeyTokenProvider(
issuerID: issuerID,
keyID: .Sample.keyID,
privateKey: key.pemRepresentation,
now: { [clock] in clock.date }
)
}
func decode(_ token: String) throws -> (header: [String: String], payload: [String: Any]) {
let parts = token.split(separator: ".").map(String.init)
try #require(parts.count == 3)
let header = try JSONDecoder().decode([String: String].self, from: try #require(Data(base64URL: parts[0])))
let payloadData = try #require(Data(base64URL: parts[1]))
let payload = try #require(try JSONSerialization.jsonObject(with: payloadData) as? [String: Any])
return (header, payload)
}
}
/// A clock whose date only changes when it is advanced.
private final class TestClock: @unchecked Sendable {
private(set) var date = Date(timeIntervalSince1970: 1_800_000_000)
func advance(by interval: TimeInterval) {
date = date.addingTimeInterval(interval)
}
}
// MARK: - Data+Base64URL
private extension Data {
init?(base64URL: String) {
var base64 = base64URL
.replacingOccurrences(of: "-", with: "+")
.replacingOccurrences(of: "_", with: "/")
base64 += String(repeating: "=", count: (4 - base64.count % 4) % 4)
self.init(base64Encoded: base64)
}
}
// MARK: - String+Samples
private extension String {
enum Sample {
static let issuerID: String = "57246542-96fe-1a63-e053-0824d011072a"
static let keyID: String = "2X9R4HXF34"
}
}
#endif
@@ -0,0 +1,173 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
import Foundation
import HTTPTypes
import OpenAPIRuntime
import Testing
// A non-testable import ensures that the sequence can be created from outside the module.
import ASConnectService
@Suite("PagedSequence")
struct PagedSequenceTests {
// MARK: Properties
private let server = Server(pages: 3)
// MARK: Tests
@Test("Fetches every page, passing the cursor of each next link")
func fetchesEveryPage() async throws {
var pages: [Int] = []
for try await page in makeSequence() {
pages.append(page.number)
}
#expect(pages == [1, 2, 3])
#expect(await server.cursors == [nil, "2", "3"])
}
@Test("Does not fetch any page until the sequence is iterated")
func fetchesLazily() async throws {
_ = makeSequence()
#expect(await server.cursors.isEmpty)
}
@Test("Finishes the iteration after a fetch throws")
func finishesAfterError() async throws {
await server.fail(atPage: 2)
var iterator = makeSequence().makeAsyncIterator()
#expect(try await iterator.next()?.number == 1)
do {
_ = try await iterator.next()
Issue.record("Fetching the second page should throw")
} catch {
#expect(error is ServerError)
}
#expect(try await iterator.next() == nil)
#expect(await server.cursors == [nil, "2"])
}
@Test("Pages through a generated operation, sending the cursor as a query parameter")
func pagesThroughGeneratedOperation() async throws {
let transport = PagedTransport()
let client = Client(
serverURL: try Servers.Server1.url(),
transport: transport
)
let pages = PagedSequence(links: \.links) { cursor in
try await client.appsGetCollection(query: .init(limit: 200, cursor: cursor)).ok.body.json
}
var count = 0
for try await _ in pages {
count += 1
}
#expect(count == 2)
#expect(await transport.paths == ["/v1/apps?limit=200", "/v1/apps?limit=200&cursor=Mg"])
}
}
// MARK: - Helpers
private extension PagedSequenceTests {
func makeSequence() -> PagedSequence<TestPage> {
let server = server
return PagedSequence(links: \.links) { cursor in
try await server.page(at: cursor)
}
}
}
/// A page of a paged operation.
private struct TestPage: Sendable {
let number: Int
let links: Components.Schemas.PagedDocumentLinks
}
/// An actor that serves a number of pages, and records the cursors it is asked for.
private actor Server {
private let pages: Int
private var failingPage: Int?
private(set) var cursors: [String?] = []
init(pages: Int) {
self.pages = pages
}
func fail(atPage page: Int) {
failingPage = page
}
func page(at cursor: String?) throws -> TestPage {
cursors.append(cursor)
let number = cursor.flatMap { Int($0) } ?? 1
if number == failingPage {
throw ServerError.unavailable
}
let base = "https://api.appstoreconnect.apple.com/v1/apps"
return TestPage(
number: number,
links: .init(
_self: base,
next: number < pages ? "\(base)?cursor=\(number + 1)" : nil
)
)
}
}
/// An error thrown by the server.
private enum ServerError: Error {
case unavailable
}
/// A transport that serves two pages of apps, and records the paths of the requests it sends.
private actor PagedTransport: ClientTransport {
private(set) var paths: [String?] = []
func send(
_ request: HTTPRequest,
body: HTTPBody?,
baseURL: URL,
operationID: String
) async throws -> (HTTPResponse, HTTPBody?) {
paths.append(request.path)
let isFirstPage = paths.count == 1
let next = isFirstPage ? #", "next": "https://api.appstoreconnect.apple.com/v1/apps?cursor=Mg&limit=200""# : ""
let json = #"{ "data": [], "links": { "self": "https://api.appstoreconnect.apple.com/v1/apps"\#(next) } }"#
return (
HTTPResponse(status: .ok, headerFields: [.contentType: "application/json"]),
HTTPBody(json)
)
}
}
+28
View File
@@ -0,0 +1,28 @@
// swift-tools-version: 6.0
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
import PackageDescription
// Development tools, kept out of the main package so consumers don't resolve them.
let package = Package(
name: "asconnect-service-tools",
platforms: [
.macOS(.v10_15)
],
dependencies: [
.package(url: "https://github.com/apple/swift-openapi-generator.git", exact: "1.11.0")
]
)