Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Canada support #83

Open
mendeljacks opened this issue Jan 5, 2022 · 2 comments
Open

Canada support #83

mendeljacks opened this issue Jan 5, 2022 · 2 comments

Comments

@mendeljacks
Copy link

When using the walmart canada marketplace api, the routes need to be modified to include the 'ca' part.
eg /v3/ca/feeds instead of /v3/feeds.

Options I considered:

  1. Is there a mechanism to re-run the generator for the ca api?
  2. or perhaps adding the ability to override the url as an optional parameter?

I would prefer option 1 since the apis are not exactly the same (eg no multi-node shipping support in canada)

ps.
I vibe with the philosophy of this package,
thanks for the great work

@josh-fisher
Copy link
Contributor

Hi @mendeljacks - Interesting issue that I had not even anticipated. Our Market is us so I did not even consider any other market. Unfortunately, It looks like the routes are not the only difference.

As you pointed out the APIs are different. In fact, they have different schemas altogether. If you look at the utils/schema-downloader.ts file you will see that country is an input param to the apiDetailUrl.

Additionally, it looks like each market has different headers (See table below) and Canada has a completely different Authentication mechanism where some java jar file has to be run to sign each call.

Header us ca mx
Authorization X   X
WM_SEC.ACCESS_TOKEN X   X
WM_CONSUMER.CHANNEL.TYPE X X X
WM_QOS.CORRELATION_ID X X X
WM_SVC.NAME X X X
WM_CONSUMER.ID   X  
WM_SEC.AUTH_SIGNATURE   X  
WM_SEC.TIMESTAMP   X  
WM_TENANT_ID   X  
WM_LOCALE_ID   X X
WM_MARKET     X

Mexico would be an easier market to implement currently as it uses the same authentication and authorization schemas, with relatively small header additions, but Canada is a completely different story.

I'm not sure how quickly we will get around to implementing Canada as it is certainly not a priority at the moment, but I will definitely make a branch and explore some ideas.

@mendeljacks
Copy link
Author

I figured out how to authenticate with only using nodejs and the built in crypto library:
(to run this you will need the three walmart environment variables)

import axios from 'axios'
import { createSign, randomBytes } from 'crypto'

const PK_HEADER = '\n-----BEGIN PRIVATE KEY-----\n'
const PK_FOOTER = '\n-----END PRIVATE KEY-----\n'

const BASE_URL = 'https://marketplace.walmartapis.com'
const WALMART_CONSUMER = '***'
const WALMART_SECRET = '***'
const WALMART_CHANNEL = '***'

const generateCorrelationId = () => {
    return randomBytes(16).toString('hex')
}

const generateSignature = (url, method, timestamp) => {
    const privateKey = `${PK_HEADER}${WALMART_SECRET}${PK_FOOTER}`

    const stringToSign =
        WALMART_CONSUMER + '\n' + url + '\n' + method.toUpperCase() + '\n' + timestamp + '\n'

    const sign = createSign('RSA-SHA256')

    sign.update(stringToSign)

    return sign.sign(privateKey, 'base64')
}

const doRequest = async (endpoint, method, body = {}) => {
    const url = BASE_URL + endpoint
    const timestamp = Date.now()
    const signature = generateSignature(url, method, timestamp)

    const headers = {
        'WM_SVC.NAME': 'Walmart Gateway API',
        'WM_CONSUMER.ID': WALMART_CONSUMER,
        'WM_SEC.TIMESTAMP': timestamp,
        'WM_SEC.AUTH_SIGNATURE': signature,
        'WM_QOS.CORRELATION_ID': generateCorrelationId(),
        'WM_CONSUMER.CHANNEL.TYPE': WALMART_CHANNEL,
        ...(method === 'post' ? { accept: 'application/json' } : {})
    }

    const response = await axios({
        method: method,
        url: url,
        data: body,
        headers: headers
    }).catch(err => {
        console.log(err?.response?.data)
        debugger
    })

    debugger
}

// Get a specific sku
doRequest('/v3/ca/items/2298', 'get')

// Update inventory
const sku = '2298'
const body = JSON.stringify({
    InventoryHeader: {
        version: '1.4'
    },
    Inventory: [
        {
            sku: 'test1',
            quantity: {
                unit: 'EACH',
                amount: 10
            }
        },
        {
            sku: '894728',
            quantity: {
                unit: 'EACH',
                amount: 20
            }
        }
    ]
})
doRequest(`/v3/ca/feeds?feedType=inventory`, 'post', { file: Buffer.from(body) })

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants