SamYoungNY SamYoungNY - 1 month ago 13
Javascript Question

Failed to load resource: the server responded with a status of 421 (Bad Request)

I am using Apple's new CloudKit JS reference and sample code to build a simple CRUD app. Before I can even get to CRUD however I am being stopped by Apple authentication.

index.html
<html>
<body>

<div id="apple-sign-in-button">Sign in
<span id="username"></span>
</div>

<script>
/*
* Initialize the global objects we will need.
*/
if(typeof CKCatalog === 'undefined') {
CKCatalog = {};
}

if(typeof CKCatalog.tabs === 'undefined') {
CKCatalog.tabs = {
'readme': [{}],
'not-found': [{}]
};
}
</script>

<script src="js/init.js"></script>
<script src="js/cloudkit-code-samples/authentication.js"></script>
<script>
window.addEventListener('cloudkitloaded',CKCatalog.init);
</script>
<script async src="https://cdn.apple-cloudkit.com/ck/1/cloudkit.js"> </script>

</body>


Including div id="apple-sign-in-button" and span id="username" got rid of all errors except:

Failed to load resource: the server responded with a status of 421 (Bad Request).

Any mention of this error anywhere else usually has it tied to SMTP or FTP. Any idea what is going on?

Answer

The CloudKit.js library is a wrapper around the CloudKit Web Services, and its documentation states that an HTTP 421 happens when a request was called that required authentication, but the user was not logged in.

This is expected as your app will likely need to determine if a user is logged in and, if not, show the appropriate Sign In button. The CloudKit Catalog example's section on Authentication shows how you can set this up by calling container.setUpAuth(), which will check for a user and render the Sign In button if none is detected. It's possible that this is happening in your init.js code, but without seeing it I can't be sure.

I see you have the apple-sign-in-button div on your page. If you're calling the setUpAuth method then you should see the Sign In button rendered inside of it.

Once a user clicks that button and signs in then you can re-issue the original request that was receiving a 421 and should get a valid 200.

Don't forget that if you want to persist the user's CloudKit session you can use auth: { persist: true } when you initialize your Container (see the CloudKit.js docs for more).

You'll also want to ensure you've created an API token in the CloudKit Dashboard for your Container. This is the token you use when you initialize your Container. Check out the WWDC 2015 video on CloudKit JS and Web Services to see a demo of this.

I hope that helps!

UPDATE:

When testing your web application, make sure that you've configured your API Token (using the CloudKit Dashboard) to allow for the domain you're testing with (e.g. localhost). This was originally Sam's problem but localhost is now a supported domain for API tokens in the Development Environment.