highsidelabs / walmart-api-php

PHP SDK for Walmart's Marketplace Partner, Content Provider, and 1P Supplier APIs.
https://highsidelabs.co
BSD 3-Clause "New" or "Revised" License
25 stars 21 forks source link

Support for nextCursor #6

Closed friendscottn closed 1 year ago

friendscottn commented 1 year ago

The Issue

When you request orders on Walmart's Orders API using the /v3/orders endpoint they return a nextCursor property in the meta response. Here's a sample of the nextCursor:

?limit=10
&hasMoreElements=true
&soIndex=18
&poIndex=10
&partnerId=10005555555
&sellerId=105555555
&createdStartDate=2023-07-17T00:00:00-06:00
&createdEndDate=2023-07-19T23:04:58.242Z
&shipNodeType=SellerFulfilled

They want you to use that for the querystring parameters of your next call to get the next page. The Walmart\Apis\MP\US\OrdersApi::getAllOrders() method needs some way to support requesting that next page of orders.

It looks like this is not the only endpoint that uses the nextCursor meta property to support pagination.

I'd be happy to create a PR for this, but first I'd like to:

  1. Confirm an acceptable solution with @jlevers
  2. Make sure what's implemented allows regeneration of the API classes using the open api generator (assuming that's a goal of this project)

Possible solution

Take a nextCursor argument on the getAllOrders method and ignore all other arguments. Just use the nextCursor as the query string for the API Call if the nextCursor is not null.

jlevers commented 1 year ago

Hey @friendscottn, thanks for the thorough bug report and solution analysis.

It looks like the reason for this problem is that Walmart just doesn't include the nextCursor parameter in their OpenAPI spec for the Marketplace Orders API. I set up the schema-corrections.json file in an effort to make it relatively easy to correct errors in Walmart's schemas in a reproducible way that wouldn't be lost every time the schemas were regenerated. You should be able to add the nextCursor parameter for the US\MP\OrdersApi::getAllOrders method there. It looks like none of the existing getAllOrders parameters are required, which I hope will make this easier.

Taking a look through the OpenAPI models, it looks like there should be a nextCursor query parameter in a couple other places, too:

There are cursors used in a bunch of other places, too, but they're just query parameter strings that should be used on the next request, rather than tokens.

A PR is definitely welcome – let me know if you need more guidance on how to get started with this.

friendscottn commented 1 year ago

Okay sounds good. I'll take a swing at it.

cnx7 commented 1 year ago

When can we handle this issue ? I need it to get the next page data.

friendscottn commented 1 year ago

Hey @cnx7 , If you want to try out the fix I've got(#8 ) you can throw this into your composer.json to pull from my repo temporarily until the PR get's merged:

{
    "minimum-stability": "dev",
    "prefer-stable": true,
    "repositories": {
        "highsidelabs/walmart-api": {
            "type": "vcs",
            "url": "https://github.com/friendscottn/walmart-api-php.git"
        },
    }
}
gio-vlasov commented 9 months ago

Any explanation of how to actually get all orders from this endpoint using multiple requests with cursor? Maybe add a method that retrieves an iterator for orders to abstract away the details of passing the cursor parameters manually?

gio-vlasov commented 9 months ago

Figured it out, you have to do ugly stuff like this:

        $ordersResponse = $ordersApi->getAllOrders();
        do {
            foreach ($ordersResponse->getList()->getElements()->getOrder() as $order) {
                yield $order;
            }
            if ($ordersResponse->getList()->getMeta()->getNextCursor() === null) {
                break;
            } else {
                $cursor = [];
                parse_str(
                    ltrim(
                        $ordersResponse->getList()->getMeta()->getNextCursor(),
                        '?'
                    ),
                    $cursor
                );
            }
            $ordersResponse = $ordersApi->getAllOrders(
                limit: $cursor['limit'],
                hasMoreElements: $cursor['hasMoreElements'],
                soIndex: $cursor['soIndex'],
                poIndex: $cursor['poIndex'],
                partnerId: $cursor['partnerId'],
                sellerId: $cursor['sellerId'],
                createdStartDate: $cursor['createdStartDate'],
                createdEndDate: $cursor['createdEndDate']
            );
        } while(true);