CloudKit JS Sample Code Error

While implementing Apple’s CloudKit Catalog, I discovered an error in the sample code for the saveRecords method under the Records item.

The example demoSaveRecords method takes a lot of possible arguments.

1
2
3
4
5
function demoSaveRecords(
databaseScope,recordName,recordChangeTag,recordType,zoneName,
forRecordName,forRecordChangeTag,publicPermission,ownerRecordName,
participants,parentRecordName,fields,createShortGUID
)

Using these parameters, the demoSaveRecords method implementation constructs a record object and an options argument that are passed to the saveRecords method on CloudKit.Database.

Within the method’s code is this offending block…

1
2
3
4
5
// Convert the fields to the appropriate format.
record.fields = Object.keys(fields).reduce(function(obj,key) {
obj[key] = { value: fields[key] };
return obj;
},{});

The is intended to create a property on the record object using the keys and values of the fields object passed in as a parameter. Presumably, the fields object you pass into the method will look like this example provided in the the CloudKit JS Reference documentation:

1
2
3
4
5
6
7
8
9
10
11
12
var record = {
recordName: '115',
recordType: 'Artwork',
fields: {
title: {
value: 'MacKerricher State Park'
},
address: {
value: 'Fort Bragg, CA'
}
}
};

Likewise, if you were to simply copy the fields property off of an existing record and provide it as the method parameter, this example is exactly how the fields property is constructed.

The problem is that the code block in Apple’s demoSaveRecords function adds an extra nested value: property to the mix. When the CloudKit.Database saveRecords method is expecting:

1
2
3
4
5
fields: {
title: {
value: 'MacKerricher State Park'
}
}

Instead it gets:

1
2
3
4
5
6
7
fields: {
title: {
value: {
value: 'MacKerricher State Park'
}
}
}

The evidence is a 400 Bad Request error that likely reads:
missing required field ‘recordName’
or
Invalid value, expected type STRING but actual value was object of class com.apple.cloudkit.ws.application.common.data.UnknownTypeModel

The fix is to simply to replace…
obj[key] = { value: fields[key] };
with
obj[key] = fields[key];