Skip to content

Commit

Permalink
Remove patches for 3.7 (#211)
Browse files Browse the repository at this point in the history
* Remove fixed patches

* Update README
  • Loading branch information
MortenGregersen authored Nov 12, 2024
1 parent 1569e91 commit 9e96d5b
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 134 deletions.
21 changes: 9 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ The OpenAPI Spec provided by Apple do not always align with the data received fr

* Submitted: January 21st 2021.
* Updated: October 14th 2022 - the type "SERVICES" is also missing.
* Partly resolved: November 12th 2024 (Spec version 3.7) - "UNIVERSAL" added.

**Title:** App Store Connect API is missing the "UNIVERSAL" type for the BundleIdPlatform schema

Expand All @@ -166,14 +167,6 @@ On 12/1/23 some errors (with status code 409) has been observed, with no `detail
In Apple's OpenAPI spec and documentation the `associatedErrors` is not mentioned in `meta` property (last checked 12/1/23).
But it is observed when creating a `ReviewSubmissionItem` with an `AppStoreVersion` fails.

#### **FB13701181**: App Store Connect API Spec is missing "DEVELOPER_ID_APPLICATION_G2" type for the Certificate Type schema

* Submitted: March 28th 2024.

In the OpenAPI spec for the App Store Connect API the “CertificateType” schema is said to not include "DEVELOPER_ID_APPLICATION_G2”. This is not right as “Certificates” endpoints can have a “DEVELOPER_ID_APPLICATION_G2” type.
When creating certificates on [the developer portal](https://developer.apple.com/account/resources/certificates/add), it is also possible to select the G2 Sub-CA (which corresponds to “DEVELOPER_ID_APPLICATION_G2”.
#### **FB15681740**: App Store Connect API Spec is missing "APPLE_VISION_PRO" type for the Device class type schema

* Submitted: November 4th 2024.
Expand All @@ -182,10 +175,6 @@ In the OpenAPI spec for the App Store Connect API the “Device.deviceClass” s
### Closed feedback (removed patches)
* **FB13540097**: Almost all of the schemas ending in “WithoutIncludesResponse” has wrong "data" type
* Submitted: January 14th 2024.
* Resolved: July 11th 2024 (Spec version 3.5).

* **FB9963088**: The xcodeMetrics schema has no properties or attributes in the OpenAPI spec
* Submitted: March 21st 2022.
* Resolved: July 12th 2022 (Spec version 2.0).
Expand All @@ -201,3 +190,11 @@ In the OpenAPI spec for the App Store Connect API the “Device.deviceClass” s
* **FB13539766**: App Store Connect API Spec is missing "APP_APPLE_VISION_PRO" type for the Screenshot Display Type schema
* Submitted: January 14th 2024.
* Resolved: January 25th 2024 (Spec version 3.2).
* **FB13540097**: Almost all of the schemas ending in “WithoutIncludesResponse” has wrong "data" type
* Submitted: January 14th 2024.
* Resolved: July 11th 2024 (Spec version 3.5).
* **FB13701181**: App Store Connect API Spec is missing "DEVELOPER_ID_APPLICATION_G2" type for the Certificate Type schema
* Submitted: March 28th 2024.
* Resolved: November 12th 2024 (Spec version 3.7).
93 changes: 35 additions & 58 deletions Sources/BagbutikSpecDecoder/Spec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,21 @@ public struct Spec: Decodable {
public mutating func addForgottenIncludeParameters() {
for (pathKey, path) in paths {
var path = path
path.operations.forEach { operation in
for operation in path.operations {
let operationIndex = path.operations.firstIndex(of: operation)!
var operation = operation
let responseSchemaName = operation.successResponseType
guard case .object(let responseSchema) = components.schemas[responseSchemaName] else { return }
guard case .object(let responseSchema) = components.schemas[responseSchemaName] else { continue }
let dataSchemaName: String
guard let dataProperty = responseSchema.properties["data"] else { return }
guard let dataProperty = responseSchema.properties["data"] else { continue }
if case .arrayOfSchemaRef(let theDataSchemaName) = dataProperty.type {
dataSchemaName = theDataSchemaName
} else if case .schemaRef(let theDataSchemaName) = dataProperty.type {
dataSchemaName = theDataSchemaName
} else { return }
} else { continue }
guard case .object(let dataSchema) = components.schemas[dataSchemaName],
case .schema(let dataRelationshipsSchema) = dataSchema.properties["relationships"]?.type
else { return }
else { continue }
let includeNamesFromResponse = dataRelationshipsSchema.properties.map(\.key)
operation.parameters?.forEach { parameter in
guard let parameterIndex = operation.parameters?.firstIndex(of: parameter),
Expand Down Expand Up @@ -122,14 +122,14 @@ public struct Spec: Decodable {
case .schema(var targetDataSchema) = targetDataProperty.type,
case .schema(var targetDataAttributesSchema) = targetDataSchema.properties["attributes"]?.type
else { return }
targetDataAttributesSchema.properties.forEach { (targetDataAttributesPropertyName: String, targetDataAttributesProperty: Property) in
for (targetDataAttributesPropertyName, targetDataAttributesProperty) in targetDataAttributesSchema.properties {
guard case .enumSchema(let targetDataAttributesPropertySchema) = targetDataAttributesProperty.type,
case .objectSchema(let mainAttributesSchema) = mainSchema.subSchemas.filter({ $0.name == "Attributes" }).first,
mainAttributesSchema.properties.contains(where: { (_: String, mainAttributesProperty: Property) in
guard case .enumSchema(let mainAttributesPropertySchema) = mainAttributesProperty.type else { return false }
return mainAttributesPropertySchema.name == targetDataAttributesPropertySchema.name
&& mainAttributesPropertySchema.cases == targetDataAttributesPropertySchema.cases
}) else { return }
}) else { continue }
targetDataAttributesSchema.properties[targetDataAttributesPropertyName] = .init(type: .schemaRef("\(mainSchemaName).Attributes.\(targetDataAttributesPropertySchema.name)"), deprecated: targetDataAttributesProperty.deprecated)
}
targetDataSchema.properties["attributes"]?.type = .schema(targetDataAttributesSchema)
Expand All @@ -146,74 +146,51 @@ public struct Spec: Decodable {
*/
public mutating func applyManualPatches() throws {
// Remove all paths with no operations
paths = paths.filter { $0.value.operations.count > 0 }

// Add the cases `UNIVERSAL` and `SERVICES` to BundleIdPlatform
// Apple's OpenAPI spec doesn't include Universal App IDs. Reported to Apple 21/1/21 as FB8977648.
paths = paths.filter { !$0.value.operations.isEmpty }

// Add the case `SERVICES` to BundleIdPlatform
// Apple's OpenAPI spec doesn't include Service IDs (like "Sign in with Apple"). Reported to Apple 14/10/22 as a later comment on FB8977648.
if case .enum(var bundleIdPlatformSchema) = components.schemas["BundleIdPlatform"] {
if !bundleIdPlatformSchema.cases.contains(where: { $0.value == "SERVICES" }) {
bundleIdPlatformSchema.cases.append(EnumCase(id: "services", value: "SERVICES", documentation: "A string that represents a service."))
}
if !bundleIdPlatformSchema.cases.contains(where: { $0.value == "UNIVERSAL" }) {
bundleIdPlatformSchema.cases.append(EnumCase(id: "universal", value: "UNIVERSAL", documentation: "A string that represents iOS and macOS."))
}
components.schemas["BundleIdPlatform"] = .enum(bundleIdPlatformSchema)
patchedSchemas.append(.enum(bundleIdPlatformSchema))
}

// Add the case `PROCESSING` to Device.Status
// Apple's OpenAPI spec doesn't include Processing as status for Device.
if case .object(var deviceSchema) = components.schemas["Device"],
var deviceAttributesSchema: ObjectSchema = deviceSchema.subSchemas.compactMap({ (subSchema: SubSchema) -> ObjectSchema? in
guard case .objectSchema(let subSchema) = subSchema,
subSchema.name == "Attributes" else {
return nil
}
return subSchema
}).first,
var statusProperty = deviceAttributesSchema.properties["status"],
case .enumSchema(var statusEnum) = statusProperty.type {
var values = statusEnum.cases
values.append(EnumCase(id: "processing", value: "PROCESSING"))
statusEnum.cases = values
statusProperty.type = PropertyType.enumSchema(statusEnum)
deviceAttributesSchema.properties["status"] = statusProperty
deviceSchema.properties["attributes"]?.type = .schema(deviceAttributesSchema)
components.schemas["Device"] = .object(deviceSchema)
patchedSchemas.append(.object(deviceSchema))
}

// Add the case `APPLE_VISION_PRO` to DeviceClass
// Apple's OpenAPI spec doesn't include the Apple Vision Pro for Device class.
if case .object(var deviceSchema) = components.schemas["Device"],
var deviceAttributesSchema: ObjectSchema = deviceSchema.subSchemas.compactMap({ (subSchema: SubSchema) -> ObjectSchema? in
guard case .objectSchema(let subSchema) = subSchema,
subSchema.name == "Attributes" else {
return nil
}
return subSchema
}).first,
var classProperty = deviceAttributesSchema.properties["deviceClass"],
case .enumSchema(var classEnum) = classProperty.type {
var values = classEnum.cases
values.append(EnumCase(id: "appleVisionPro", value: "APPLE_VISION_PRO"))
classEnum.cases = values
classProperty.type = PropertyType.enumSchema(classEnum)
deviceAttributesSchema.properties["deviceClass"] = classProperty
deviceSchema.properties["attributes"]?.type = .schema(deviceAttributesSchema)
components.schemas["Device"] = .object(deviceSchema)
patchedSchemas.append(.object(deviceSchema))
}

// Add the case `DEVELOPER_ID_APPLICATION_G2` to CertificateType
// Apple's OpenAPI spec doesn't include the role for generating individual keys. Reported to Apple 28/3/24 as FB13701181.
if case .enum(var certificateTypeSchema) = components.schemas["CertificateType"] {
if !certificateTypeSchema.cases.contains(where: { $0.value == "DEVELOPER_ID_APPLICATION_G2" }) {
certificateTypeSchema.cases.append(EnumCase(id: "developerIdApplicationG2", value: "DEVELOPER_ID_APPLICATION_G2"))
}).first {
// Add the case `PROCESSING` to Device.Status
// Apple's OpenAPI spec doesn't include Processing as status for Device.
if var statusProperty = deviceAttributesSchema.properties["status"],
case .enumSchema(var statusEnum) = statusProperty.type {
var values = statusEnum.cases
values.append(EnumCase(id: "processing", value: "PROCESSING"))
statusEnum.cases = values
statusProperty.type = PropertyType.enumSchema(statusEnum)
deviceAttributesSchema.properties["status"] = statusProperty
deviceSchema.properties["attributes"]?.type = .schema(deviceAttributesSchema)
components.schemas["Device"] = .object(deviceSchema)
}
components.schemas["CertificateType"] = .enum(certificateTypeSchema)
patchedSchemas.append(.enum(certificateTypeSchema))
// Add the case `APPLE_VISION_PRO` to DeviceClass
// Apple's OpenAPI spec doesn't include the Apple Vision Pro for Device class.
if var classProperty = deviceAttributesSchema.properties["deviceClass"],
case .enumSchema(var classEnum) = classProperty.type {
var values = classEnum.cases
values.append(EnumCase(id: "appleVisionPro", value: "APPLE_VISION_PRO"))
classEnum.cases = values
classProperty.type = PropertyType.enumSchema(classEnum)
deviceAttributesSchema.properties["deviceClass"] = classProperty
deviceSchema.properties["attributes"]?.type = .schema(deviceAttributesSchema)
components.schemas["Device"] = .object(deviceSchema)
}
patchedSchemas.append(.object(deviceSchema))
}

// Fix up the names of the sub schemas of ErrorResponse.Errors
Expand Down
65 changes: 1 addition & 64 deletions Tests/BagbutikSpecDecoderTests/SpecTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ final class SpecTests: XCTestCase {
},
"BundleIdPlatform" : {
"type" : "string",
"enum" : [ "IOS", "MAC_OS" ]
"enum" : [ "IOS", "MAC_OS", "UNIVERSAL" ]
},
"Device" : {
"type" : "object",
Expand Down Expand Up @@ -885,7 +885,6 @@ final class SpecTests: XCTestCase {
}
let bundleIdPlatformCaseValues = bundleIdPlatformSchema.cases.map(\.value)
XCTAssertEqual(bundleIdPlatformCaseValues.count, 4)
XCTAssertTrue(bundleIdPlatformCaseValues.contains("UNIVERSAL"))
XCTAssertTrue(bundleIdPlatformCaseValues.contains("SERVICES"))

guard case .object(let deviceSchema) = spec.components.schemas["Device"],
Expand Down Expand Up @@ -941,68 +940,6 @@ final class SpecTests: XCTestCase {
XCTAssertTrue(kidsAgeBandProperty.clearable)
}

func testApplyManualPatches_MissingCertificateType() throws {
let specString = """
{
"paths": {},
"components": {
"schemas": {
"ErrorResponse" : {
"type" : "object",
"properties" : {
"errors" : {
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"id" : {
"type" : "string"
},
"status" : {
"type" : "string"
},
"code" : {
"type" : "string"
},
"title" : {
"type" : "string"
},
"detail" : {
"type" : "string"
},
"source" : {
"oneOf" : [ {
"$ref" : "#/components/schemas/ErrorSourcePointer"
}, {
"$ref" : "#/components/schemas/ErrorSourceParameter"
} ]
}
},
"required" : [ "code", "detail", "title", "status" ]
}
}
}
},
"CertificateType" : {
"type" : "string",
"enum" : [ "DISTRIBUTION", "DEVELOPMENT", "DEVELOPER_ID_APPLICATION" ]
}
}
}
}
"""
let jsonDecoder = JSONDecoder()
var spec = try jsonDecoder.decode(Spec.self, from: specString.data(using: .utf8)!)
try spec.applyManualPatches()

guard case .enum(let certificateTypeSchema) = spec.components.schemas["CertificateType"] else {
XCTFail(); return
}
let certificateTypeCaseValues = certificateTypeSchema.cases.map(\.value)
XCTAssertEqual(certificateTypeCaseValues.count, 4)
XCTAssertTrue(certificateTypeCaseValues.contains("DEVELOPER_ID_APPLICATION_G2"))
}

func testApplyManualPatches_Error() throws {
let specString = """
{
Expand Down

0 comments on commit 9e96d5b

Please sign in to comment.