fix(aso): omit null attributes in beta app review submit body (#31)
Apple's betaAppReviewSubmissions endpoint 422s (ENTITY_UNPROCESSABLE) when data.attributes is present but null. The create body built its POST with the generic CreateBody/CreateData whose attributes: () serialized to "attributes": null. Introduce dedicated local CreateBody/CreateData/CreateRelationships carrying only the build relationship (no attributes field), mirroring the review_submission.rs pattern. Replace the misleading test that asserted the buggy null with one asserting attributes is absent. Co-authored-by: siGit Code v1.6.7-acp <noreply@sigit.si>
Seto Elkahfi committed
Oct 12, 2026 at 01:20 UTC
592bfc7e7fc6bd01884622a769ccb3ffd81d45ce
1 file changed
+40
-12
crates/aso/src/beta_app_review_submission.rs
+40
-12
@@ -14,9 +14,7 @@
14
use async_trait::async_trait;
15
use reqwest::Method;
16
use serde::{Deserialize, Serialize};
17
-use smbcloud_ascapi_core::jsonapi::{
18
- CreateBody, CreateData, Document, ListDocument, Resource, ResourceId, ToOne,
19
-};
17
+use smbcloud_ascapi_core::jsonapi::{Document, ListDocument, Resource, ResourceId, ToOne};
18
use smbcloud_ascapi_core::Client;
19
use smbcloud_ascapi_core::Result;
20
@@ -51,6 +49,23 @@ pub type BetaAppReviewSubmission = Resource<BetaAppReviewSubmissionAttributes>;
49
50
// ── internal create helper ────────────────────────────────────────────────────
51
52
+/// A beta app review submission carries only a `build` relationship. Apple's
53
+/// endpoint rejects a request whose `data.attributes` is present but null
54
+/// (422 `ENTITY_UNPROCESSABLE`), so this body omits the field entirely rather
55
+/// than reusing [`smbcloud_ascapi_core::jsonapi::CreateBody`] with `()`
56
+/// attributes.
57
+#[derive(Debug, Clone, Serialize)]
58
+struct CreateBody {
59
+ data: CreateData,
60
+}
61
+
62
+#[derive(Debug, Clone, Serialize)]
63
+struct CreateData {
64
+ #[serde(rename = "type")]
65
+ resource_type: &'static str,
66
+ relationships: CreateRelationships,
67
+}
68
+
69
#[derive(Debug, Clone, Serialize)]
70
struct CreateRelationships {
71
build: ToOne,
@@ -99,15 +114,14 @@ impl BetaAppReviewSubmissionsApi for Client {
114
let body = CreateBody {
115
data: CreateData {
116
resource_type: RESOURCE_TYPE,
102
- attributes: (),
103
- relationships: Some(CreateRelationships {
117
+ relationships: CreateRelationships {
118
build: ToOne {
119
data: ResourceId {
120
resource_type: crate::build::RESOURCE_TYPE,
121
id: build_id.to_string(),
122
},
123
},
110
- }),
124
+ },
125
},
126
};
127
let doc: Document<BetaAppReviewSubmissionAttributes> = self
@@ -196,17 +210,31 @@ mod tests {
210
}
211
212
#[test]
199
- fn create_body_attributes_unit_serializes() {
200
- // The create body has no attributes — verify `()` round-trips cleanly.
213
+ fn create_body_omits_attributes() {
214
+ // Apple's endpoint 422s on a null `data.attributes`; the body must omit
215
+ // the field entirely and carry only the `build` relationship.
216
let body = CreateBody {
217
data: CreateData {
218
resource_type: RESOURCE_TYPE,
204
- attributes: (),
205
- relationships: None::<()>,
219
+ relationships: CreateRelationships {
220
+ build: ToOne {
221
+ data: ResourceId {
222
+ resource_type: crate::build::RESOURCE_TYPE,
223
+ id: "BUILD_ID".to_string(),
224
+ },
225
+ },
226
+ },
227
},
228
};
229
let v = serde_json::to_value(&body).unwrap();
209
- // `()` serialises as `null`; the key is present in the object.
210
- assert!(v["data"]["attributes"].is_null());
230
+ assert!(
231
+ v["data"].get("attributes").is_none(),
232
+ "attributes must be omitted, not null: {v}"
233
+ );
234
+ assert_eq!(v["data"]["type"], RESOURCE_TYPE);
235
+ assert_eq!(
236
+ v["data"]["relationships"]["build"]["data"]["id"],
237
+ "BUILD_ID"
238
+ );
239
}
240
}