Shopify / js-buy-sdk

The JS Buy SDK is a lightweight library that allows you to build ecommerce into any website. It is based on Shopify's API and provides the ability to retrieve products and collections from your shop, add products to a cart, and checkout.
https://shopify.github.io/js-buy-sdk
MIT License
994 stars 263 forks source link

Unable to create a checkout #379

Closed adpcris closed 7 years ago

adpcris commented 7 years ago

Using v1.0alpha version When creating an empty checkout like in the example:

client.createCheckout().then((checkout) => {
  console.log(checkout);
});

I get the following error:

Uncaught (in promise) TypeError: Cannot read property 'checkoutCreate' of undefined

which comes from:

function checkoutMutation(type, input, query, client) {
  var mutation = client.mutation(function (root) {
    root.add(type, { args: input }, function (checkoutMutationField) {
      checkoutMutationField.add('userErrors', function (userErrors) {
        userErrors.add('message');
        userErrors.add('field');
      });
      query(checkoutMutationField, 'checkout');
    });
  });
  return client.send(mutation).then(function (result) {
    var userErrors = result.data[type].userErrors; // => error comes from this line, as data is undefined
    if (userErrors.length) {
      return Promise.reject(new Error(JSON.stringify(userErrors)));
    }
    return client.fetchAllPages(result.model[type].checkout.lineItems, { pageSize: 250 }).then(function (lineItems) {
      result.model[type].checkout.attrs.lineItems = lineItems;
      return result.model[type].checkout;
    });
  });
}

Note that client is previously created and I'm able to fetch products and collections normally. What am I missing?

I appreciate any help. Thank you

swalkinshaw commented 7 years ago

Are you using the latest v1.0.0-alpha.9? This might be a bug we fixed in that release.

Please try upgrading first and let us know if it still happens or not.

adpcris commented 7 years ago

Hi @swalkinshaw

I did upgrade to v1.0.0-alpha.9, but the problem persisted. At the end I realised the problem was due to not using the correct token (I was using the Buy button one, instead of the SDK).

Other functions like fetchProduct or fetchAllCollectionsWithProducts were working fine with the buy button token. For some reason the js would fire the error about a missing property of 'checkoutCreate' instead of letting you know it was due to lack of permissions.

Thanks for your interest. Cristina

swalkinshaw commented 7 years ago

Glad you got it working 👍

For some reason the js would fire the error about a missing property of 'checkoutCreate' instead of letting you know it was due to lack of permissions.

I think we're lacking some error handling. The response from the server likely contained an error which JS Buy SDK should do a better job of notifying users about.

doublerebel commented 7 years ago

Using v1.0.0-alpha.9 this issue manifests itself as:

Cannot read property 'userErrors' of null

TypeError: Cannot read property 'userErrors' of null
    at /.../node_modules/shopify-buy/index.js:3017:39
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:169:7)
grep -rin usererrors node_modules/shopify-buy/index.js
...
3017:    var userErrors = result.data[type].userErrors;
...

Which is the compiled version of https://github.com/Shopify/js-buy-sdk/blob/v1.0alpha/src/client.js#L39 .

Inspecting result we get:

{ data: { checkoutCreate: null },
  errors: 
   [ { message: 'CheckoutCreate access denied',
       locations: [Array],
       path: [Array] } ],
  model: GraphModel { attrs: { checkoutCreate: null, type: [Object] } } }

So there are some useful errors, they're just in .errors and not passed along.

swalkinshaw commented 7 years ago

@doublerebel great debugging. Are you running into that issue too? CheckoutCreate should not return access denied if you're using a Storefront Access Token created via a Private App (the flow recommended in our docs).

doublerebel commented 7 years ago

@swalkinshaw after going through all of this a few times and getting it running, it appears the issue that causes this is yes, using the Buy Button api key with 1.0alpha.

I think the confusion is that the official docs say to use a storefrontAccessToken, which I did at first -- but I also installed the package from npm npm i shopify-buy, not realizing there was an alpha version. Putting the storefrontAccessToken into version 0.7 gives vague errors like:

{ Error: Not Found
    at checkStatus (/home/charles/source/temp2/node_modules/shopify-buy/lib/shopify.js:1130:15)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:169:7)
  status: 404,
  response: 
   Response {
     url: 'https://exampleshop.myshopify.com/api/apps/6/product_listings',
     ...

So then I went back and put the Buy button key in, which works fine for product calls. Later when I ran into checkout problems, I found the alpha version and upgraded the library and config, never thinking the key would have to change. So I can see how this would happen to someone else.

It would be really nice if the library versions could catch the mismatched key but I don't know if that's possible. Stripe has a habit of prefixing all their keys so that they are harder to mix up, which has saved me before.

doublerebel commented 7 years ago

I accidentally attempted (using v1.0.0-alpha.9) to modify a checkout that was already purchased, and that error is swallowed as well with:

Cannot read property 'userErrors' of null

TypeError: Cannot read property 'userErrors' of null
    at /.../node_modules/shopify-buy/index.js:3017:39
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:169:7)

But again if I inspect result.errors I get:

[ { message: 'Checkout is already completed.',
    locations: [ [Object] ],
    path: [ 'checkoutLineItemsAdd' ] } ]
swalkinshaw commented 7 years ago

@doublerebel yeah I mentioned in another comment that the alpha version isn't doing a good job of surfacing errors. We discussed a little bit internally last week and it's something we'll add soon.

Likely we'll just reject the Promise and it will be easy to see the errors.

It would be really nice if the library versions could catch the mismatched key but I don't know if that's possible. Stripe has a habit of prefixing all their keys so that they are harder to mix up, which has saved me before.

I don't think that's possible unfortunately. We have a longer term goal of improving our permissions/access scopes to better document them and expose them through GraphQL errors too. Right now it's a bit of a black box as you've run into.

okwme commented 7 years ago

why is the buy-button token denied access on createCheckout? is that not in scope for that token? I don't have a store front sales channel, does that mean i can't use checkouts?

minasmart commented 7 years ago

buy button does not have that scope. If you create a private app, and check the box marked Allow Access To Storefront Data, you'll get a token with all the required scopes. You will be able to create and modify checkouts (which behave like carts). Processing a credit card though, still requires you to send the user over to the checkout URL, which is a property on the checkout object, and will reflect all the data you've already set up.

okwme commented 7 years ago

Do you need a store front sales channel for that? I'm just using the buy button sales channel with the lite plan and my API calls return an empty set of products and collections even though I've approved read access in my app settings.

minasmart commented 7 years ago

you do not need online store. Creating a private app with access to storefront data makes that private app something you can publish products to. it is effectively a channel. If you're getting empty arrays, you likely need to publish your products and collections.

okwme commented 7 years ago

good call @minasmart thanks!

corvuszero commented 1 year ago

This caught me by surprise recently. @swalkinshaw comment was the most useful one. In my particular case I was using the Javascript Buy SDK v1 and just needed to upgrade to v2 in addition to doing the necessary tweaks to correctly use variant price amount and currency code.