pwa-kit icon indicating copy to clipboard operation
pwa-kit copied to clipboard

[FEATURE] Add more details about API error

Open LucasReyre opened this issue 1 year ago • 5 comments

Is your feature request related to a problem? Please describe.

It seems that there is currently no way to retrieve the body of an API request in error. This is a real pain point as I have customized some SCAPI endpoint and return custom status code like :

{
    "title": "Hook Status",
    "type": "https://api.commercecloud.salesforce.com/documentation/error/v1/errors/hook-status",
    "detail": "An error occurred in ExtensionPoint 'dw.ocapi.shop.basket.items.afterPOST'.",
    "extensionPoint": "dw.ocapi.shop.basket.items.afterPOST",
    "statusCode": "add_to_cart_not_allowed",
    "statusMessage": "add_to_cart_not_allowed",
    "statusDetails": {}
}

And I would like to display custom messages on the front-end depending on this statusCode.

Describe the solution you'd like I would like the possibility to get back the API's body from the SDK.

LucasReyre avatar Feb 09 '24 14:02 LucasReyre

Thanks @LucasReyre.

Using SCAPI hooks to add details to error message with Script API's Status and status.addDetail is very useful to provide support for conditional error messages based on SCAPI hook invocation success.

If you drop down to the level of commerce-sdk-isomorphic are you able to see the error message?

I'm curious about where in the stack you've observed the details being lost.

Thanks!

johnboxall avatar Feb 09 '24 15:02 johnboxall

I'm not comfortable enough with commerce-sdk to investigate this module. But I have observed that in the pwa-kit addItemToBasketMutation.mutateAsync throws the following exception when a response other than in success is received.

image

LucasReyre avatar Feb 09 '24 16:02 LucasReyre

To build on the issue, commerce-sdk-isomorphic does provide access to custom validation errors returned by SCAPI, so we should validate that the error body is available in commerce-sdk-react.

To replicate ...

  1. In a cartridge, create a hook that throw an error:
// dw.ocapi.shop.category.beforeGET
exports.beforeGET = function errorWithDetails() {
    const status = new Status(Status.ERROR)
    status.addDetail("validation_error", "Naughty Category")
    return status
}
  1. In the ISO SDK, you can see you can pull out the error:
import capi from "commerce-sdk-isomorphic"

function getClientConfig() {
    return {
        parameters: {
            shortCode: "kv7kzm78",
            organizationId: "f_ecom_zzrf_016",
            siteId: "RefArch",
            clientId: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
        },
        throwOnBadResponse: true,
    }
}

async function main() {
    const clientConfig = getClientConfig()
    const shopperLoginClient = new capi.ShopperLogin(clientConfig)

    // 1️⃣ Login as a guest.
    const guestTokenResponse = await capi.helpers.loginGuestUserPrivate(
        shopperLoginClient,
        {},
        { clientSecret: "REDACTED" }
    )
    clientConfig.headers = {
        Authorization: `Bearer ${guestTokenResponse.access_token}`,
    }

    // 2️⃣ Make a call to categories which throws an error.
    try {
        await new capi.ShopperProducts(clientConfig).getCategory({
            parameters: { id: "root", levels: 0 },
        })
    } catch (err) {
        console.error({ errData: await err.response.json() })
    }
}

main()

johnboxall avatar Mar 11 '24 22:03 johnboxall

Hi @LucasReyre @johnboxall !

Thank you for bringing this up. To build on John's point, you can grab error from the commerce-sdk-isomorphic level but it's very unintuitive to access errors from the commerce-sdk-react hooks.

Yes, there is a way to access API errors!

There is a way to grab errors and althou it isn't the prettiest way.

const product = useProduct(
        {parameters: {id: '25502228Mxxx'}},
        {
            onError: async (error) => {
                // access error properties in json
                const json = await error.response.json()
                console.log(json)
            }
        }
    )

CleanShot 2024-03-18 at 10 22 11

There is a playground app where you can reproduce this -> https://github.com/SalesforceCommerceCloud/pwa-kit/compare/demo-commerce-sdk-react-error-handling?expand=1

But, it should be better!

As you may already found out, the above method uses a callback function that doesn't play well with react states.

Ideally it should be very easy to access errors like this:

const product = useProduct({parameters: {id: '25502228Mxxx'}})

console.log(product.error)

I'm going to create a bug ticket in our system to fix this issue. In the meantime, please use the callback method to access error. Thank you!

kevinxh avatar Mar 18 '24 17:03 kevinxh

Hello @kevinxh

The way you catch the error details works well, I will use it until you release something easier.

Thanks to you two

LucasReyre avatar Mar 19 '24 14:03 LucasReyre