janhommes / o.js

o.js - client side oData lib.
https://janhommes.github.io/o.js/example/
MIT License
241 stars 58 forks source link

Batch And ChangeSet #94

Closed DrYSG closed 4 years ago

DrYSG commented 5 years ago

Do you have an example of using Batch and ChangeSets?

I have an ODATA provider (EPICOR ERP), that has an broken POST update method,.

So instead I want to Batch together an ODATA DELETE With an POST (of a replacement of the record) and do this an an atomic operation.

I am under the impression that I need to use BATCH and ChangeSet to do this.

Here is are current DELETE and POST methods I use:

/**
 * EPICOR invoke ODATA Delete command
 * @param {string} serviceBO - Busines Object that provides service
 * @param {string} args - the ODATA command and any arguments
 * @param {json} query - ODATA query object (e.g. {$filter: `UserName eq 'foobar'`})
 * @return {string} The next job number
 * @public
 */
const kill = (async (serviceBO) => {
    let reply = {}
    const url = SERVERURL + serviceBO
    const options = window.STORE.getState().identity.options
    try {
        reply = await o(url, options).delete().query()
    } catch (error) {
        console.log(`Error Code: ${error.status}`)
        console.log(`Error URL: ${error.url}`)
        const json = await error.json()
        const body  = JSON.stringify(json, ' ', 4)
        console.log(`Error body: ${body}`)
        return error
    }
    return reply
})

/**
 * EPICOR invoke ODATA Post command
 * @param {string} serviceBO - Busines Object that provides service
 * @param {string} args - the ODATA command and any arguments
 * @param {json} payload - and data to send in POST
 * @return {string} The next job number
 * @public
 */
const post = (async (serviceBO, args, payload) => {
    let reply = {}
    const url = SERVERURL + serviceBO
    const options = window.STORE.getState().identity.options
    try {
        reply = await o(url, options).post(args, payload).query()
    } catch (error) {
        console.log(`Error Code: ${error.status}`)
        console.log(`Error URL: ${error.url}`)
        const json = await error.json()
        const body  = JSON.stringify(json, ' ', 4)
        console.log(`Error body: ${body}`)
        return error
    }
    return reply
})
janhommes commented 5 years ago

Mh, so the idea is that you combine them and call batch(). So in your example smth like:

const patch = (async (serviceBO, args, payload) => {
    let reply = {}
    const url = SERVERURL + serviceBO
    const options = window.STORE.getState().identity.options
    try {
        reply = await o(url, options).delete(args).post(args, payload).batch()
    } catch (error) {
        console.log(`Error Code: ${error.status}`)
        console.log(`Error URL: ${error.url}`)
        const json = await error.json()
        const body  = JSON.stringify(json, ' ', 4)
        console.log(`Error body: ${body}`)
        return error
    }
    return reply
})

So the issue is that I didn't manage to get test it correctly, as I had issues with the example oauth implementation. There are also some configurations you can do in the options that might be relevant.

Would be nice to get some feedback if it worked or if smth is missing there.

DrYSG commented 5 years ago

I thought I had to use change sets to be able to get an atomic transaction?

janhommes commented 5 years ago

yes, I gues so too. But I never ha the possibility to test it out completly.

that call builds a batch request with changsets:

o('http://myservice/', { batch: { useChangset: true, boundaryPrefix: 'bound', changsetBoundaryPrefix: 'changeset', endpoint: '$batch'} } ).post('a', {a:1} ).post('b', {b:2} ).batch()

leads to the following body:

--bound76ebc383-4171-4dd1-ad59-36291d2332bdundefined
Content-Type: multipart/mixed; boundary=changeset4654bb25-daa4-4a98-b7e3-4c208ac74fe6

--changeset4654bb25-daa4-4a98-b7e3-4c208ac74fe6
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 1

POST http://myservice/a HTTP/1.1

      {"a":1}

--changeset4654bb25-daa4-4a98-b7e3-4c208ac74fe6
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 2

POST http://myservice/b HTTP/1.1

      {"b":2}

--changeset4654bb25-daa4-4a98-b7e3-4c208ac74fe6--

--bound76ebc383-4171-4dd1-ad59-36291d2332bd--

So it looks quite okay. Only thing which I am curious about is the undefined in the first line. I guess it's because I just tested in the browser and there is no headers implementation. Maybe you can try this?

max-huster commented 4 years ago

Hey, i have the following problem:

The issue is in the boundary=changeset_8ec4720b-9476-4420-ab48-797ab0a1db6f in the header should be boundary=batch_7ed33119-70da-47e9-d400-3adbd9f7f694. There is also an "undefined" suffix like in your example (https://github.com/janhommes/o.js/issues/94?_pjax=%23js-repo-pjax-container#issuecomment-530410601)

The API i am calling reports: "Incomplete batch request body."

Here is my Request:

POST http://sapb1entw:50001/b1s/v2/$batch HTTP/1.1
OData-Version: 4.0
Content-Type: multipart/mixed; boundary=changeset_35bbf218-71b1-4e75-d15a-485ad4a58127
Accept: */*
Content-Length: 1395
User-Agent: node-fetch/1.0 (+https://github.com/bitinn/node-fetch)
Accept-Encoding: gzip,deflate
Host: sapb1entw:50001
Connection: close

--batch_7ed33119-70da-47e9-d400-3adbd9f7f694undefined
Content-Type: multipart/mixed; boundary=changeset_35bbf218-71b1-4e75-d15a-485ad4a58127

--changeset_35bbf218-71b1-4e75-d15a-485ad4a58127
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 1

POST http://sapb1entw:50001/b1s/v2/Quotations HTTP/1.1

      {"json": "here"}

--changeset_35bbf218-71b1-4e75-d15a-485ad4a58127
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 2

POST http://sapb1entw:50001/b1s/v2/Quotations(1069)/Cancel HTTP/1.1

      null

--changeset_35bbf218-71b1-4e75-d15a-485ad4a58127--

--batch_7ed33119-70da-47e9-d400-3adbd9f7f694--

I've configured my OdataBatchConfig like this:

boundaryPrefix: "batch_",
changsetBoundaryPrefix: "changeset_",
useChangset: true

I will create a Pull Request that fixes this problem.

janhommes commented 4 years ago

@max-huster with your PR can we close this?