### Complete Workflow Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md A comprehensive example demonstrating a typical workflow: listing apps, retrieving a specific app, updating it, and fetching its related store versions. ```APIDOC ## Workflow: List, Get, Update, and Fetch Related Resources ### 1. List Apps #### Description Retrieves a list of apps with specified sorting, fields, and limit. #### Method GET #### Endpoint /v1/apps #### Parameters ##### Query Parameters - **sort** (Array) - Optional - Sorting order for the apps. - **fields[apps]** (Array) - Optional - Specific fields to include for the apps. - **limit** (Int) - Optional - The maximum number of resources to return. #### Request Example ```swift let listRequest = APIEndpoint.v1.apps.get(parameters: .init( sort: [.bundleID], fieldsApps: [.name, .bundleID], limit: 5 )) ``` ### 2. Get First App #### Description Retrieves a single app by its ID. #### Method GET #### Endpoint /v1/apps/{id} #### Parameters ##### Path Parameters - **id** (String) - Required - The unique identifier of the app. #### Request Example ```swift // Assuming 'appsResponse' contains data from the previous step guard let firstApp = appsResponse.data.first else { return } let getRequest = APIEndpoint.v1.apps.id(firstApp.id).get() ``` ### 3. Update App #### Description Updates an existing app's attributes, such as its name. #### Method PATCH #### Endpoint /v1/apps/{id} #### Parameters ##### Path Parameters - **id** (String) - Required - The unique identifier of the app to update. ##### Request Body - **attributes** (AppUpdateRequest.Attributes) - Required - The attributes to update. - **name** (String) - Required - The new name for the app. #### Request Example ```swift let updateRequest = AppUpdateRequest( attributes: .init(name: "Updated Name") ) let updateEndpoint = APIEndpoint.v1.apps.id(firstApp.id).patch(updateRequest) ``` ### 4. Get Related App Store Versions #### Description Retrieves a list of app store versions associated with a specific app. #### Method GET #### Endpoint /v1/apps/{id}/appStoreVersions #### Parameters ##### Path Parameters - **id** (String) - Required - The unique identifier of the app. ##### Query Parameters - **limit** (Int) - Optional - The maximum number of resources to return. #### Request Example ```swift let versionsRequest = APIEndpoint.v1.apps.id(firstApp.id) .appStoreVersions .get(parameters: .init(limit: 3)) ``` ``` -------------------------------- ### Fetch Apps Collection Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/types.md An example demonstrating how to fetch a collection of apps with a specified limit using the SDK. This utilizes the generic collection response structure. ```swift let request = APIEndpoint.v1.apps.get(parameters: .init(limit: 10)) let appsResponse = try await provider.request(request) print("Apps: \(appsResponse.data.count)") ``` -------------------------------- ### Perform API Request to Get Apps Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/README.md Create an APIProvider instance with your configuration and make a request to fetch apps. This example demonstrates fetching apps with specific fields and sorting. ```swift let request = APIEndpoint .v1 .apps .get(parameters: .init( sort: [.bundleID], fieldsApps: [.appInfos, .name, .bundleID], limit: 5 )) let apps = try await self.provider.request(request).data print("Did fetch \(apps.count) apps") ``` -------------------------------- ### Import App Store Connect SDK Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/README.md Import the necessary framework to start using the SDK. ```swift import AppStoreConnect_Swift_SDK ``` -------------------------------- ### Pagination Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md Demonstrates how to control the page size of results using the `limit` parameter for the `apps` endpoint. ```APIDOC ## Pagination Control page size: ```swift let request = APIEndpoint.v1.apps.get(parameters: .init( limit: 20 )) ``` ``` -------------------------------- ### Initialize and Use App Store Connect Swift SDK Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/00_START_HERE.md This snippet shows the basic steps to configure the SDK with your credentials, create an API provider, and make a request to get a list of apps. Ensure you replace placeholder values with your actual issuer ID, key ID, and base64-encoded private key. ```swift import AppStoreConnect_Swift_SDK // 1. Create configuration let config = try APIConfiguration( issuerID: "your-issuer-id", privateKeyID: "your-key-id", privateKey: "base64-encoded-key" ) // 2. Create provider let provider = APIProvider(configuration: config) // 3. Make a request let request = APIEndpoint.v1.apps.get(parameters: .init(limit: 10)) let appsResponse = try await provider.request(request) // 4. Use the response for app in appsResponse.data { print("App: \(app.attributes?.name ?? "")") } ``` -------------------------------- ### RateLimit Example Entries Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/RateLimit.md Illustrates the expected format of the 'entries' dictionary, mapping metric names to their integer values. ```swift [ "max-requests": 40, "requests": 38, "remaining": 2, "expires-after": 3600 ] ``` -------------------------------- ### Install jq for OpenAPI Generation Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/README.md Install the `jq` command-line JSON processor using Homebrew. This tool is a prerequisite for updating the OpenAPI generated code. ```bash brew install jq ``` -------------------------------- ### Breaking Early Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/PagedRequest.md Demonstrates how to stop iterating through pages before all are fetched. ```APIDOC ## Breaking Early ```swift for try await appsResponse in provider.paged(request) { if appsResponse.data.count > 100 { break // Stop iterating after first page with >100 items } processApps(appsResponse.data) } ``` ``` -------------------------------- ### Secure API Configuration Setup Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/README.md Demonstrates how to securely load API credentials from environment variables to configure the SDK. Ensure these environment variables are set before running the application. ```swift guard let issuerID = ProcessInfo.processInfo.environment["ASC_ISSUER_ID"], let keyID = ProcessInfo.processInfo.environment["ASC_KEY_ID"], let keyData = ProcessInfo.processInfo.environment["ASC_PRIVATE_KEY"] else { fatalError("Missing ASC credentials") } let configuration = try APIConfiguration( issuerID: issuerID, privateKeyID: keyID, privateKey: keyData ) ``` -------------------------------- ### Basic Iteration Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/PagedRequest.md Demonstrates how to iterate over paginated results using a for-await loop. ```APIDOC ## Basic Iteration ```swift let request = APIEndpoint.v1.apps.get(parameters: .init( sort: [.bundleID], limit: 10 )) for try await pagedResult in provider.paged(request) { let apps = pagedResult.data print("Received \(apps.count) apps") } ``` ``` -------------------------------- ### RateLimit Initialization Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/RateLimit.md Demonstrates how to create a RateLimit object from a raw header string and a request URL. The 'entries' property will be populated based on the parsed header value. ```swift let rateLimit = RateLimit( value: "max-requests:40, max-concurrent-requests:10, requests:38, remaining:2, reset-after:3600", requestURL: URL(string: "https://api.appstoreconnect.apple.com/v1/apps") ) // entries = [ // "max-requests": 40, // "max-concurrent-requests": 10, // "requests": 38, // "remaining": 2, // "reset-after": 3600 // ] ``` -------------------------------- ### Get Single Resource Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md Construct a request to retrieve a single resource by its ID, optionally specifying which fields to return. This is used for fetching details of a specific item. ```swift let request = APIEndpoint.v1.apps.id("123").get( fieldsApps: [.name, .bundleID] ) let appResponse = try await provider.request(request) if let app = appResponse.data { print("App: \(app.attributes?.name ?? "")") } ``` -------------------------------- ### List Resources Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md Construct a request to list multiple resources, specifying sorting, fields, and limits. This pattern is used for retrieving collections of data. ```swift let request = APIEndpoint.v1.apps.get(parameters: .init( sort: [.bundleID], fieldsApps: [.name, .bundleID], limit: 10 )) let appsResponse = try await provider.request(request) print("Apps: \(appsResponse.data.count)") ``` -------------------------------- ### Complete App Management Workflow Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md A comprehensive example showing a typical workflow: listing apps, retrieving a specific app, updating it, and then fetching its related store versions. This covers common CRUD operations and relationship traversal. ```swift // 1. List apps let listRequest = APIEndpoint.v1.apps.get(parameters: .init( sort: [.bundleID], fieldsApps: [.name, .bundleID], limit: 5 )) let appsResponse = try await provider.request(listRequest) // 2. Get first app guard let firstApp = appsResponse.data.first else { return } let getRequest = APIEndpoint.v1.apps.id(firstApp.id).get() let appResponse = try await provider.request(getRequest) // 3. Update app let updateRequest = AppUpdateRequest( attributes: .init(name: "Updated Name") ) let updateEndpoint = APIEndpoint.v1.apps.id(firstApp.id).patch(updateRequest) try await provider.request(updateEndpoint) // 4. Get related versions let versionsRequest = APIEndpoint.v1.apps.id(firstApp.id) .appStoreVersions .get(parameters: .init(limit: 3)) let versionsResponse = try await provider.request(versionsRequest) ``` -------------------------------- ### Request Construction with APIEndpoint Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/Request.md Demonstrates how to create different types of requests (collection GET, specific resource GET, PATCH, DELETE) using the APIEndpoint helper methods. ```APIDOC ## Request Construction with APIEndpoint Requests are typically not constructed directly. Instead, they're returned from `APIEndpoint` helpers: ```swift // GET collection let getRequest = APIEndpoint.v1.apps.get(parameters: .init(limit: 5)) // GET specific resource let getOneRequest = APIEndpoint.v1.apps.id("123").get() // PATCH let patchRequest = APIEndpoint.v1.apps.id("123").patch(.init(...)) // DELETE let deleteRequest = APIEndpoint.v1.apps.id("123").delete() ``` Then requests are passed to provider methods: ```swift let apps = try await provider.request(getRequest) ``` ``` -------------------------------- ### Error Handling Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/PagedRequest.md Illustrates how to handle potential errors during paginated requests. ```APIDOC ## With Error Handling ```swift do { for try await appsResponse in provider.paged(request) { // Process each page processApps(appsResponse.data) } } catch let error as APIProvider.Error { switch error { case .requestFailure(let statusCode, _, _): print("Request failed: \(statusCode)") case .decodingError: print("Invalid response format") default: print("Error: \(error)") } } ``` ``` -------------------------------- ### Field Selection Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md Demonstrates how to use the `fieldsApps` parameter to select specific fields for the `apps` endpoint, reducing the payload size. ```APIDOC ## Field Selection Use `fieldsApps` to select specific fields and reduce payload: ```swift let request = APIEndpoint.v1.apps.get(parameters: .init( fieldsApps: [.name, .bundleID], // Only these attributes limit: 5 )) ``` ``` -------------------------------- ### Subscribing to Rate Limit Updates Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIProvider.md Example of how to subscribe to the `rateLimitPublisher` to receive and log rate limit information. Ensure you manage Combine subscriptions appropriately. ```swift provider.rateLimitPublisher .sink { print("Rate limit entries: \(rateLimit.entries)") } .store(in: &subscriptions) ``` -------------------------------- ### Create Resource Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md Construct a request to create a new resource by providing the necessary attributes in a request body. This is used for adding new items to the App Store Connect API. ```swift let createRequest = AppCreateRequest( attributes: .init(name: "MyApp", bundleID: "com.example.myapp", sku: "ABC123") ) let request = APIEndpoint.v1.apps.post(createRequest) let createdApp = try await provider.request(request) ``` -------------------------------- ### Collecting All Results Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/PagedRequest.md Shows how to collect all items from paginated responses into a single array. ```APIDOC ## Collecting All Results ```swift var allApps: [App] = [] for try await appsResponse in provider.paged(request) { allApps.append(contentsOf: appsResponse.data) } print("Total: \(allApps.count) apps") ``` ``` -------------------------------- ### Sorting Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md Illustrates how to sort results by a field in ascending or descending order using the `sort` parameter for the `apps` endpoint. ```APIDOC ## Sorting Sort by field ascending or descending: ```swift let request = APIEndpoint.v1.apps.get(parameters: .init( sort: [.bundleID, .nameReverse] )) ``` ``` -------------------------------- ### Example JWT Authorization Header Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/JWTRequestsAuthenticator.md Illustrates the format of the JWT bearer token used in the Authorization header. ```text Authorization: Bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IjJYOVI0SFhGMzQiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiI1NzI0NjU0Mi05NmZlLTFhNjMtZTA1My0wODI0ZDAxMTA3MmEiLCJleHAiOjE1OTI5NDEyMDAsImF1ZCI6ImFwcHN0b3JlY29ubmVjdC12MSJ9.signature ``` -------------------------------- ### Get Single App Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md Shows how to retrieve a specific app by its ID, including selecting specific fields. ```APIDOC ## Get Single App ### Description Constructs a request to retrieve a specific app by its unique identifier, with the option to specify which fields to return. ### Method `GET` ### Endpoint `/v1/apps/{id}` ### Parameters #### Path Parameters - **id** (String) - Required - The unique identifier of the app. #### Query Parameters - **fieldsApps** (Array) - Optional - Specifies which attributes to include for the app. ### Request Example ```swift let request = APIEndpoint.v1.apps.id("123").get( fieldsApps: [.name, .bundleID] ) ``` ``` -------------------------------- ### Accessing Rate Limit Information Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/types.md Example of how to subscribe to rate limit updates and print the remaining request count. Requires a publisher and a subscription management mechanism. ```swift provider.rateLimitPublisher.sink { rateLimit in print("Remaining: \(rateLimit.entries["remaining"] ?? 0)") }.store(in: &subscriptions) ``` -------------------------------- ### Monitoring Rate Limits with Publishers Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/errors.md Subscribe to the rateLimitPublisher to monitor remaining API requests. This example prints a warning when the number of remaining requests drops below a threshold. ```swift provider.rateLimitPublisher.sink { rateLimit in let remaining = rateLimit.entries["remaining"] ?? 0 if remaining < 5 { print("⚠️ Only \(remaining) requests remaining") } }.store(in: &subscriptions) ``` -------------------------------- ### Execute Data Request with DefaultRequestExecutor Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/DefaultRequestExecutor.md Execute a URLRequest and receive raw data in the completion handler. This example demonstrates handling both successful responses with data and potential errors. ```swift let executor = DefaultRequestExecutor() var request = URLRequest(url: URL(string: "https://api.appstoreconnect.apple.com/v1/apps")!) request.httpMethod = "GET" executor.execute(request) { result in switch result { case .success(let response): print("Status: \(response.statusCode)") if let data = response.data { print("Data: \(data.count) bytes") } case .failure(let error): print("Error: \(error)") } } ``` -------------------------------- ### Constructing API Requests with APIEndpoint Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/Request.md Requests are typically not constructed directly but are returned from APIEndpoint helpers. This demonstrates common GET, PATCH, and DELETE request constructions. ```swift // GET collection let getRequest = APIEndpoint.v1.apps.get(parameters: .init(limit: 5)) // GET specific resource let getOneRequest = APIEndpoint.v1.apps.id("123").get() // PATCH let patchRequest = APIEndpoint.v1.apps.id("123").patch(.init(...)) // DELETE let deleteRequest = APIEndpoint.v1.apps.id("123").delete() ``` -------------------------------- ### Update Resource Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md Construct a request to update an existing resource by providing the resource ID and the updated attributes in a request body. This is used for modifying existing items. ```swift let updateRequest = AppUpdateRequest( attributes: .init(name: "Updated Name") ) let request = APIEndpoint.v1.apps.id("123").patch(updateRequest) try await provider.request(request) ``` -------------------------------- ### Request Initialization (No Body) Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/Request.md Initializes a Request object for API calls that do not require a request body, such as GET or DELETE requests. Specify the API path, HTTP method, optional query parameters, custom headers, and a unique request ID. ```swift public init( path: String, method: String, query: [(String, String?)]? = nil, headers: [String: String]? = nil, id: String ) ``` ```swift let request = Request( path: "/v1/apps", method: "GET", query: [("filter[id]", "123"), ("limit", "10")], id: "apps_getCollection" ) ``` -------------------------------- ### Fetch Next Page with Callback using `request(_:pageAfter:completion:)` Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIProvider.md Use the `request(_:pageAfter:completion:)` method to fetch the next page of results when using a callback-based approach. Provide the original request and the current page's data to get the subsequent page. ```swift let firstPageRequest = APIEndpoint.v1.apps.get(parameters: .init(limit: 2)) provider.request(firstPageRequest) { result in guard case .success(let firstPage) = result else { return } provider.request(firstPageRequest, pageAfter: firstPage) { nextResult in if case .success(let secondPage) = nextResult { print("Next page: \(secondPage?.data.count ?? 0) items") } } } ``` -------------------------------- ### Typical Configuration and API Request Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/configuration.md Demonstrates the standard workflow: creating an API configuration with issuer ID, private key ID, and private key, then initializing an API provider and making a request for apps. ```swift import AppStoreConnect_Swift_SDK // 1. Create configuration let configuration = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyID: "2X9R4HXF34", privateKey: "MIGfMA0GCSqGSIb3...", expirationDuration: 900 // 15 minutes ) // 2. Create provider let provider = APIProvider(configuration: configuration) // 3. Make requests let request = APIEndpoint.v1.apps.get(parameters: .init(limit: 10)) let apps = try await provider.request(request) ``` -------------------------------- ### Custom Executor Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/RequestExecutor.md An example of a custom RequestExecutor that logs requests and responses. ```APIDOC ## LoggingRequestExecutor ### Description A custom executor that wraps another executor to log outgoing requests and incoming responses. ### Initialization ```swift init(wrapping executor: RequestExecutor = DefaultRequestExecutor()) ``` ### Methods #### execute(_:completion:) Logs the request and then calls the wrapped executor's execute method. #### download(_:completion:) Calls the wrapped executor's download method. ### Usage Example ```swift class LoggingRequestExecutor: RequestExecutor { let wrapped: RequestExecutor init(wrapping executor: RequestExecutor = DefaultRequestExecutor()) { self.wrapped = executor } func execute(_ urlRequest: URLRequest, completion: @escaping (Result, Error>) -> Void) { print("→ \(urlRequest.httpMethod ?? \"GET\") \(urlRequest.url?.path ?? \"\")") wrapped.execute(urlRequest) { result in switch result { case .success(let response): print("← \(response.statusCode)") case .failure(let error): print("← Error: \(error)") } completion(result) } } func download(_ urlRequest: URLRequest, completion: @escaping (Result, Error>) -> Void) { wrapped.download(urlRequest, completion: completion) } } // Usage let loggingExecutor = LoggingRequestExecutor() let provider = APIProvider(configuration: config, requestExecutor: loggingExecutor) ``` -------------------------------- ### APIConfiguration Initialization and Usage Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIConfiguration.md Demonstrates how to initialize the APIConfiguration with your credentials and use it to create an APIProvider instance. ```APIDOC ## Usage Configurations are passed to `APIProvider` during initialization: ```swift let configuration = try APIConfiguration( issuerID: "your-issuer-id", privateKeyID: "your-key-id", privateKey: "your-base64-key" ) let provider = APIProvider(configuration: configuration) ``` ``` -------------------------------- ### File-Based Configuration Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/configuration.md Shows how to configure the SDK using a private key file (.p8). Ensure the file path is correct and the file is readable by the application. ```swift let fileURL = URL(fileURLWithPath: "/path/to/AuthKey_2X9R4HXF34.p8") let config = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyURL: fileURL ) ``` -------------------------------- ### Example API Error Response JSON Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/errors.md Illustrates a typical JSON structure for an error response from the App Store Connect API. This example shows a 'Bad Request' error with a specific field validation issue. ```json { "errors": [ { "id": "8f6a2ab1-a3bc-4a38-90f7-d6c3fb9ce52f", "status": "400", "code": "INVALID_FIELD_VALUE", "title": "Bad Request", "detail": "The provided name is too long (max 30 characters)", "source": { "pointer": "/data/attributes/name" } } ] } ``` -------------------------------- ### Initialize APIConfiguration and APIProvider Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIConfiguration.md Demonstrates how to initialize APIConfiguration with JWT details and then use it to create an APIProvider instance. ```swift let configuration = try APIConfiguration( issuerID: "your-issuer-id", privateKeyID: "your-key-id", privateKey: "your-base64-key" ) let provider = APIProvider(configuration: configuration) ``` -------------------------------- ### Initialize APIConfiguration for Individual Accounts with Key File URL Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIConfiguration.md This initializer is for individual developer accounts using a .p8 private key file. The private key ID can be inferred from the filename if not provided. File access and key validation errors are possible. ```swift let config = try APIConfiguration( privateKeyURL: URL(fileURLWithPath: "/path/to/AuthKey_2X9R4HXF34.p8") ) ``` -------------------------------- ### Filtering Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md Shows how to filter results by a list of IDs using the `filterID` parameter for the `actors` endpoint. ```APIDOC ## Filtering Filter results by ID: ```swift let request = APIEndpoint.v1.actors.get(parameters: .init( filterID: ["actor-123", "actor-456"] )) ``` ``` -------------------------------- ### Create API Configuration with Private Key File Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/README.md Initialize API configuration using your Issuer ID and the file path to your private key (.p8) file. The SDK will load the key from the specified URL. ```swift let configuration = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyURL: URL(fileURLWithPath: "~/AuthKey_2X9R4HXF34.p8") ) ``` -------------------------------- ### Task Cancellation Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/PagedRequest.md Shows how task cancellation affects the `next()` method, causing it to return `nil`. ```APIDOC ## Task Cancellation ```swift let task = Task { for try await appsResponse in provider.paged(request) { processApps(appsResponse.data) } } // Later, cancel the iteration task.cancel() // next() returns nil immediately ``` ``` -------------------------------- ### Initialize APIConfiguration with File (Team Account) Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/configuration.md Use this initializer when the private key is stored in a .p8 file. If `privateKeyID` is not provided, it will be inferred from the filename. The file must be readable by the application. ```swift try APIConfiguration( issuerID: String, privateKeyID: String? = nil, privateKeyURL: URL, expirationDuration: TimeInterval = 1200 ) ``` ```swift // With explicit ID let config = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyID: "2X9R4HXF34", privateKeyURL: URL(fileURLWithPath: "~/AuthKey_2X9R4HXF34.p8") ) // ID inferred from filename let config2 = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyURL: URL(fileURLWithPath: "~/AuthKey_2X9R4HXF34.p8") ) // privateKeyID automatically set to "2X9R4HXF34" ``` -------------------------------- ### Create App Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md Illustrates how to create a new app resource with its required attributes. ```APIDOC ## Create App ### Description Constructs a request to create a new app resource. Requires a request body containing the app's attributes. ### Method `POST` ### Endpoint `/v1/apps` ### Parameters #### Request Body - **attributes** (AppCreateRequest.Attributes) - Required - The attributes for the new app. ### Request Example ```swift let createRequest = AppCreateRequest(attributes: .init(name: "MyApp", bundleID: "com.example.myapp", sku: "ABC123")) let request = APIEndpoint.v1.apps.post(createRequest) ``` ``` -------------------------------- ### Initialize APIConfiguration with Private Key File URL Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIConfiguration.md This initializer is used when your private key is stored in a .p8 file. You can provide the private key ID explicitly, or it will be inferred from the filename if omitted. Ensure the file is accessible and contains a valid P256 key. ```swift let config = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyID: "2X9R4HXF34", privateKeyURL: URL(fileURLWithPath: "/path/to/AuthKey_2X9R4HXF34.p8") ) ``` ```swift let config2 = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyURL: URL(fileURLWithPath: "/path/to/AuthKey_2X9R4HXF34.p8") ) // privateKeyID extracted as "2X9R4HXF34" ``` -------------------------------- ### init(issuerID:privateKeyID:privateKeyURL:expirationDuration:) Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIConfiguration.md Initializes APIConfiguration from a PEM-encoded .p8 private key file. The private key ID can be provided explicitly or inferred from the filename. ```APIDOC ## init(issuerID:privateKeyID:privateKeyURL:expirationDuration:) ### Description Creates a configuration from a PEM-encoded .p8 private key file. This initializer is useful when the private key is stored in a file. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **issuerID** (`String`) - Required - Issuer ID from App Store Connect - **privateKeyID** (`String?`) - Optional - Private key ID; inferred from filename if nil (last 10 chars before extension). Defaults to nil. - **privateKeyURL** (`URL`) - Required - File URL to the .p8 private key file - **expirationDuration** (`TimeInterval`) - Optional - Token expiration in seconds. Defaults to 1200 (20 minutes). ### Throws - File access errors if URL cannot be read - `JWT.Error.invalidPrivateKey`: File does not contain a valid P256 key - `JWT.Error.invalidExpirationDuration`: Duration outside valid range ### Example ```swift // With explicit private key ID let config = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyID: "2X9R4HXF34", privateKeyURL: URL(fileURLWithPath: "/path/to/AuthKey_2X9R4HXF34.p8") ) // Private key ID inferred from filename let config2 = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyURL: URL(fileURLWithPath: "/path/to/AuthKey_2X9R4HXF34.p8") ) // privateKeyID extracted as "2X9R4HXF34" ``` ``` -------------------------------- ### Initialize APIConfiguration with File (Individual Account) Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/configuration.md Use this initializer for individual developer accounts when the private key is stored in a .p8 file. The `privateKeyID` can be inferred from the filename if not explicitly provided. The file must be readable by the application. ```swift try APIConfiguration( individualPrivateKeyID: String? = nil, privateKeyURL: URL, expirationDuration: TimeInterval = 1200 ) ``` ```swift let config = try APIConfiguration( privateKeyURL: URL(fileURLWithPath: "~/AuthKey_2X9R4HXF34.p8") ) // ID extracted as "2X9R4HXF34" ``` -------------------------------- ### Get a Single Resource by ID Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/README.md Retrieve a specific resource, such as an app, by its unique identifier. The response will contain the details of the requested resource. ```swift let request = APIEndpoint.v1.apps.id("123").get() let appResponse = try await provider.request(request) if let app = appResponse.data { print("App: \(app.attributes?.name ?? "")") } ``` -------------------------------- ### Delete Resource Example Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md Construct a request to delete a specific resource by its ID. This is used for removing items from the App Store Connect API. ```swift let request = APIEndpoint.v1.apps.id("123").delete() try await provider.request(request) ``` -------------------------------- ### List Apps Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIEndpoint.md Demonstrates how to construct a request to list apps with specific parameters. ```APIDOC ## List Apps ### Description Constructs a request to retrieve a list of apps, allowing for sorting, field selection, and limiting the number of results. ### Method `GET` ### Endpoint `/v1/apps` ### Parameters #### Query Parameters - **sort** (Array) - Optional - Sorting order for the apps. - **fieldsApps** (Array) - Optional - Specifies which attributes to include for each app. - **limit** (Int) - Optional - The maximum number of resources to return. ### Request Example ```swift let request = APIEndpoint.v1.apps.get(parameters: .init( sort: [.bundleID], fieldsApps: [.name, .bundleID], limit: 10 )) ``` ``` -------------------------------- ### Request Initialization (No Body) Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/Request.md Initializes a Request object for API calls that do not require a request body. This is suitable for operations like GET or DELETE. ```APIDOC ## Request Initialization (No Body) ### `init(path:method:query:headers:id:)` ```swift public init( path: String, method: String, query: [(String, String?)]? = nil, headers: [String: String]? = nil, id: String ) ``` Creates a request with no body. | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | path | `String` | — | API path relative to base URL (e.g., "/v1/apps") | | method | `String` | — | HTTP method: "GET", "POST", "PATCH", "DELETE" | | query | `[(String, String?)]?` | `nil` | Query parameters as tuples of (key, value) | | headers | `[String: String]?` | `nil` | Custom HTTP headers | | id | `String` | — | Unique identifier for the request (API operation ID) | **Example:** ```swift let request = Request( path: "/v1/apps", method: "GET", query: [("filter[id]", "123"), ("limit", "10")], id: "apps_getCollection" ) ``` ``` -------------------------------- ### init(individualPrivateKeyID:privateKeyURL:expirationDuration:) Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIConfiguration.md Initializes APIConfiguration for individual accounts from a PEM .p8 file. The private key ID can be provided or inferred from the filename. ```APIDOC ## init(individualPrivateKeyID:privateKeyURL:expirationDuration:) ### Description Creates a configuration for individual accounts from a PEM .p8 file. This initializer is useful when the individual private key is stored in a file. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **individualPrivateKeyID** (`String?`) - Optional - Private key ID; inferred from filename if nil. Defaults to nil. - **privateKeyURL** (`URL`) - Required - File URL to .p8 private key file - **expirationDuration** (`TimeInterval`) - Optional - Token expiration in seconds. Defaults to 1200 (20 minutes). ### Throws File access and key validation errors. ### Example ```swift let config = try APIConfiguration( privateKeyURL: URL(fileURLWithPath: "/path/to/AuthKey_2X9R4HXF34.p8") ) ``` ``` -------------------------------- ### Configure API and Create Provider Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/JWT.md Initialize APIConfiguration with issuer ID, private key ID, and private key. Then, create an APIProvider using this configuration. The provider automatically handles JWT signing for requests. ```swift let configuration = try APIConfiguration( issuerID: "...", privateKeyID: "...", privateKey: "..." ) let provider = APIProvider(configuration: configuration) let result = try await provider.request(endpoint) ``` -------------------------------- ### File-Based Configuration from Secure Location Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/configuration.md Demonstrates a secure approach to file-based configuration by locating the private key file within the application's library directory. ```swift // Use secure file locations let documentsDir = FileManager.default.urls( for: .libraryDirectory, in: .userDomainMask )[0] let keyPath = documentsDir.appendingPathComponent("asc_key.p8") let configuration = try APIConfiguration( issuerID: "...", privateKeyURL: keyPath ) ``` -------------------------------- ### Initialize APIProvider Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIProvider.md Creates a new APIProvider instance. Requires API credentials and configuration. The request executor can be customized. ```swift let configuration = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyID: "2X9R4HXF34", privateKey: "MIGfMA0GCSqGSIb3..." ) let provider = APIProvider(configuration: configuration) ``` -------------------------------- ### Catch Unknown Response Type Error Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/errors.md Provides an example of how to catch the `unknownResponseType` error. This is typically used when a network request executor encounters an unexpected response format. ```swift catch DefaultRequestExecutor.Error.unknownResponseType { print("Response is not an HTTP response") } ``` -------------------------------- ### init(individualPrivateKeyID:individualPrivateKey:expirationDuration:) Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIConfiguration.md Initializes APIConfiguration for individual developer accounts using an individual private key ID and its base64-encoded value. ```APIDOC ## init(individualPrivateKeyID:individualPrivateKey:expirationDuration:) ### Description Creates a configuration for individual developer accounts using individual keys. This initializer is used when you have the individual private key as a string. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **individualPrivateKeyID** (`String`) - Required - Private key ID for individual account - **individualPrivateKey** (`String`) - Required - Base64-encoded individual private key without PEM headers - **expirationDuration** (`TimeInterval`) - Optional - Token expiration in seconds. Defaults to 1200 (20 minutes). ### Throws Same as standard `init` (base64 and key validation errors). ### Note Individual keys do not require an issuer ID. ### Example ```swift let config = try APIConfiguration( individualPrivateKeyID: "2X9R4HXF34", individualPrivateKey: "MIGfMA0GCSqGSIb3..." ) ``` ``` -------------------------------- ### Loading Private Key from Environment Variable Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/configuration.md A best practice for security: load the private key and other credentials from environment variables instead of hardcoding them. Ensure the environment variables are set. ```swift // Load from environment guard let privateKey = ProcessInfo.processInfo .environment["ASC_PRIVATE_KEY"] else { fatalError("ASC_PRIVATE_KEY not set") } let configuration = try APIConfiguration( issuerID: ProcessInfo.processInfo .environment["ASC_ISSUER_ID"]!, privateKeyID: ProcessInfo.processInfo .environment["ASC_KEY_ID"]!, privateKey: privateKey ) ``` -------------------------------- ### Iterate and Print Error Details Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/types.md Example of iterating through an array of ResponseError objects and printing their code, title, and details. Used for displaying specific error information to the user. ```swift for error in errorResponse?.errors ?? [] { print("Error \(error.code): \(error.title)") if let detail = error.detail { print(" Details: \(detail)") } } ``` -------------------------------- ### Handle API Request Failures Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/types.md Example of how to catch and process API errors, specifically extracting details from an ErrorResponse. This is used in catch blocks when API requests fail. ```swift catch let error as APIProvider.Error { if case .requestFailure(_, let errorResponse, _) = error { errorResponse?.errors?.forEach { error in print("Code: \(error.code), Title: \(error.title)") } } } ``` -------------------------------- ### init(issuerID:privateKeyID:privateKey:expirationDuration:) Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIConfiguration.md Initializes APIConfiguration with issuer ID, private key ID, base64-encoded private key, and an optional expiration duration. This method is suitable for providing credentials directly. ```APIDOC ## init(issuerID:privateKeyID:privateKey:expirationDuration:) ### Description Creates a configuration with issuer ID and base64-encoded private key. This initializer is used when you have the private key as a string. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **issuerID** (`String`) - Required - Issuer ID from App Store Connect API Keys page (e.g., "57246542-96fe-1a63-e053-0824d011072a") - **privateKeyID** (`String`) - Required - Private key ID from the API Keys page (e.g., "2X9R4HXF34") - **privateKey** (`String`) - Required - Base64-encoded private key without PEM headers - **expirationDuration** (`TimeInterval`) - Optional - Token expiration in seconds; must be between 0 and 1200. Defaults to 1200 (20 minutes). ### Throws - `JWT.Error.invalidBase64EncodedPrivateKey`: Private key is not valid base64 - `JWT.Error.invalidPrivateKey`: Private key cannot be parsed as P256 key - `JWT.Error.invalidExpirationDuration`: Duration is outside [0, 1200] range ### Example ```swift let configuration = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyID: "2X9R4HXF34", privateKey: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ...", expirationDuration: 900 // 15 minutes ) ``` ``` -------------------------------- ### Create API Configuration with Private Key String Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/README.md Initialize API configuration using your Issuer ID, Private Key ID, and the private key content directly. Ensure the private key string is correctly formatted. ```swift import AppStoreConnect_Swift_SDK let configuration = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyID: "2X9R4HXF34", privateKey: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQK..." ) ``` -------------------------------- ### Initialize APIConfiguration with String Key (Individual Account) Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/configuration.md Use this initializer for individual developer accounts when the private key is available as a base64-encoded string. It requires the `individualPrivateKeyID` and `individualPrivateKey`. Validation is the same as for team accounts. ```swift try APIConfiguration( individualPrivateKeyID: String, individualPrivateKey: String, expirationDuration: TimeInterval = 1200 ) ``` ```swift let config = try APIConfiguration( individualPrivateKeyID: "2X9R4HXF34", individualPrivateKey: "MIGfMA0GCSqGSIb3...", expirationDuration: 900 ) ``` -------------------------------- ### Iterate Over Paginated Responses with `paged(_:)` Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIProvider.md Use the `paged(_:)` method to get an async sequence for iterating over all pages of a paginated API response. This is useful when you need to process all items from a paginated endpoint. ```swift let request = APIEndpoint.v1.apps.get(parameters: .init( sort: [.bundleID], limit: 2 )) var allApps: [App] = [] for try await pagedResult in provider.paged(request) { allApps.append(contentsOf: pagedResult.data) } print("Total apps: \(allApps.count)") ``` -------------------------------- ### Configure API Access with Private Key URL Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/README.md Configure the SDK by providing the URL to your private key file (.p8). The private key ID can be inferred from the filename. ```swift let configuration = APIConfiguration(issuerID: "", privateKeyID: "", privateKeyURL: URL(fileURLWithPath: "~/AuthKey_.p8")) ``` -------------------------------- ### APIProvider Initialization Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIProvider.md Initializes a new APIProvider instance with the provided API configuration and an optional request executor. ```APIDOC ## init(configuration:requestExecutor:) ### Description Creates a new APIProvider instance for performing API requests. ### Parameters #### Path Parameters - **configuration** (`APIConfiguration`) - Required - API credentials and configuration including issuer ID, private key ID, and private key - **requestExecutor** (`RequestExecutor`) - Optional - Custom executor for URL requests; defaults to URL session-based executor ### Example ```swift let configuration = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyID: "2X9R4HXF34", privateKey: "MIGfMA0GCSqGSIb3..." ) let provider = APIProvider(configuration: configuration) ``` ``` -------------------------------- ### Initialize APIConfiguration with Base64 Private Key Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIConfiguration.md Use this initializer when you have your private key as a base64-encoded string. Ensure the key is valid base64 and can be parsed as a P256 key. The expiration duration must be between 0 and 1200 seconds. ```swift let configuration = try APIConfiguration( issuerID: "57246542-96fe-1a63-e053-0824d011072a", privateKeyID: "2X9R4HXF34", privateKey: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ...", expirationDuration: 900 // 15 minutes ) ``` -------------------------------- ### Initialize APIConfiguration for Individual Accounts with Base64 Key Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIConfiguration.md Use this initializer for individual developer accounts when the private key is available as a base64-encoded string. Issuer ID is not required for individual accounts. Key validation errors may occur. ```swift let config = try APIConfiguration( individualPrivateKeyID: "2X9R4HXF34", individualPrivateKey: "MIGfMA0GCSqGSIb3..." ) ``` -------------------------------- ### Configure API Access with Private Key Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/README.md Configure the SDK with your API issuer ID, private key ID, and the private key content. Ensure the private key is correctly formatted and whitespace is removed. ```swift let configuration = APIConfiguration(issuerID: "", privateKeyID: "", privateKey: "") ``` -------------------------------- ### Download OpenAPI Specification Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/README.md Manually download the App Store Connect OpenAPI specification using the `OpenAPIGenerator` tool. ```bash swift run OpenAPIGenerator download ``` -------------------------------- ### Make a Request to List Apps Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/README.md Construct and execute a request to list apps, specifying sorting, fields, and a limit. The response contains a collection of app data. ```swift // List apps let request = APIEndpoint.v1.apps.get(parameters: .init( sort: [.bundleID], fieldsApps: [.name, .bundleID], limit: 10 )) let appsResponse = try await provider.request(request) print("Apps: \(appsResponse.data.map { $0.attributes?.name ?? "" })") ``` -------------------------------- ### download(_:) (async) Source: https://github.com/avdlee/appstoreconnect-swift-sdk/blob/master/_autodocs/api-reference/APIProvider.md Executes an API request to download a file. ```APIDOC ## `download(_:)` (async) ### Description Async/await version for downloading files. ### Method Signature ```swift public func download(_ endpoint: Request) async throws -> URL where T: Decodable ``` ### Parameters #### Path Parameters - **endpoint** (`Request`) - Required - The API endpoint request ### Return Type `URL` to the downloaded file. ### Throws `APIProvider.Error.downloadError` on failure. ### Example ```swift let fileURL = try await provider.download(request) ``` ```