5

I have a Javascript application generating an XML and sending it to a REST API. The API is expecting content type: application/xml. I have tried to attach the XML to the requests in different formats:

    import {create} from 'xmlbuilder2';

    const rawXML = '<?xml version="1.0" encoding="UTF-8"?><TokenExchangeRequest xmlns="http://schemas.nav.gov.hu/OSA/2.0/api"><header><requestId>202003201315421</requestId><timestamp>2020-03-20T13:15:42.941Z</timestamp><requestVersion>2.0</requestVersion><headerVersion>1.0</headerVersion></header><user><login>vbdznuownd8murm</login><passwordHash>D6CD2AF6CD5912B800EC3050477E788C84804800A0235E93C7B47A436FD730504BFC979F44EB4C745F2968FE35772E1193F95BDC8DDFDC998A18C7E9E9718F28</passwordHash><taxNumber>66604093</taxNumber><requestSignature>EE265DA5AC4ADA7BBAD2D15581AA230CE50C90D9B7075814866BD43E92B30BCC0E52BA8355E0A09AB38F33D5EF7B502983ACBC5E42532C5EB8479BFDE5031AD2</requestSignature></user><software><softwareId>123456789123456789</softwareId><softwareName>placeholder</softwareName><softwareOperation>LOCAL_SOFTWARE</softwareOperation><softwareMainVersion>placeholder</softwareMainVersion><softwareDevName>placeholder</softwareDevName><softwareDevContact>placeholder</softwareDevContact><softwareDevCountryCode>HU</softwareDevCountryCode><softwareDevTaxNumber>placeholder</softwareDevTaxNumber></software></TokenExchangeRequest>'
    let parser = new DOMParser();
    let parserXML  = parser.parseFromString(rawXML, "application/xml");
    let xmlbuilderXML = create(rawXML);


    fetch('https://api-test.onlineszamla.nav.gov.hu/invoiceService/v2/tokenExchange', {
        method: 'POST', // *GET, POST, PUT, DELETE, etc.
        mode: 'no-cors', // no-cors, *cors, same-origin
        cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
        credentials: 'same-origin', // include, *same-origin, omit
        headers: {
        'Content-Type': 'application/xml',
          'accept': 'application/xml'
          // 'Content-Type': 'application/x-www-form-urlencoded',
        },
        redirect: 'follow', // manual, *follow, error
        referrerPolicy: 'no-referrer', // no-referrer, *client
        body: rawXML // body data type must match "Content-Type" header
      });

The response I get:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><GeneralExceptionResponse xmlns="http://schemas.nav.gov.hu/OSA/2.0/api" xmlns:ns2="http://schemas.nav.gov.hu/OSA/2.0/data"><funcCode>ERROR</funcCode><errorCode>OPERATION_FAILED</errorCode><message>RESTEASY003065: Cannot consume content type</message></GeneralExceptionResponse>

When I try to make the same call from Postman with the raw string as the xml body, the server can parse it and sends the appropriate response:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<GeneralErrorResponse xmlns="http://schemas.nav.gov.hu/OSA/2.0/api" xmlns:ns2="http://schemas.nav.gov.hu/OSA/2.0/data">
    <result>
        <funcCode>ERROR</funcCode>
        <errorCode>INVALID_REQUEST</errorCode>
        <message>Helytelen kérés!</message>
    </result>
    <technicalValidationMessages>
        <validationResultCode>ERROR</validationResultCode>
        <validationErrorCode>SCHEMA_VIOLATION</validationErrorCode>
        <message>Request body contains error: [cvc-pattern-valid: Value 'login' is not facet-valid with respect to pattern '[a-zA-Z0-9]{6,15}' for type 'LoginType'.]</message>
    </technicalValidationMessages>
    <technicalValidationMessages>
        <validationResultCode>ERROR</validationResultCode>
        <validationErrorCode>SCHEMA_VIOLATION</validationErrorCode>
        <message>Field [login] contains error: [cvc-type.3.1.3: The value 'login' of element 'login' is not valid.]</message>
    </technicalValidationMessages>
    <technicalValidationMessages>
        <validationResultCode>ERROR</validationResultCode>
        <validationErrorCode>SCHEMA_VIOLATION</validationErrorCode>
        <message>Request body contains error: [cvc-pattern-valid: Value '' is not facet-valid with respect to pattern '[0-9A-F]{128}' for type 'Sha512HashType'.]</message>
    </technicalValidationMessages>
    <technicalValidationMessages>
        <validationResultCode>ERROR</validationResultCode>
        <validationErrorCode>SCHEMA_VIOLATION</validationErrorCode>
        <message>Field [passwordHash] contains error: [cvc-type.3.1.3: The value '' of element 'passwordHash' is not valid.]</message>
    </technicalValidationMessages>
    <technicalValidationMessages>
        <validationResultCode>ERROR</validationResultCode>
        <validationErrorCode>SCHEMA_VIOLATION</validationErrorCode>
        <message>Request body contains error: [cvc-pattern-valid: Value '' is not facet-valid with respect to pattern '[0-9A-F]{128}' for type 'Sha512HashType'.]</message>
    </technicalValidationMessages>
    <technicalValidationMessages>
        <validationResultCode>ERROR</validationResultCode>
        <validationErrorCode>SCHEMA_VIOLATION</validationErrorCode>
        <message>Field [requestSignature] contains error: [cvc-type.3.1.3: The value '' of element 'requestSignature' is not valid.]</message>
    </technicalValidationMessages>
</GeneralErrorResponse>

Here the ERROR means that the server has PARSED the xml and has determined that the data INSIDE the XML in insufficient. This is because a proper request would contain sensitive data, which I will not share for obvious reasons.

Postman collection:

{
    "info": {
        "_postman_id": "9e2f2870-d35b-45b0-8d35-a81d190a8679",
        "name": "NAV",
        "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
    },
    "item": [
        {
            "name": "tokenExchange",
            "request": {
                "method": "POST",
                "header": [
                    {
                        "key": "Content-Type",
                        "name": "Content-Type",
                        "value": "application/xml",
                        "type": "text"
                    },
                    {
                        "key": "accept",
                        "value": "application/xml",
                        "type": "text"
                    }
                ],
                "body": {
                    "mode": "raw",
                    "raw": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<TokenExchangeRequest xmlns=\"http://schemas.nav.gov.hu/OSA/2.0/api\">\n    <header>\n        <requestId>202003201315421</requestId>\n        <timestamp>2020-03-20T13:15:42.941Z</timestamp>\n        <requestVersion>2.0</requestVersion>\n        <headerVersion>1.0</headerVersion>\n    </header>\n    <user>\n        <login>login</login>\n        <passwordHash></passwordHash>\n        <taxNumber>12345678</taxNumber>\n        <requestSignature></requestSignature>\n    </user>\n    <software>\n        <softwareId>123456789123456789</softwareId>\n        <softwareName>placeholder</softwareName>\n        <softwareOperation>LOCAL_SOFTWARE</softwareOperation>\n        <softwareMainVersion>placeholder</softwareMainVersion>\n        <softwareDevName>placeholder</softwareDevName>\n        <softwareDevContact>placeholder</softwareDevContact>\n        <softwareDevCountryCode>HU</softwareDevCountryCode>\n        <softwareDevTaxNumber>placeholder</softwareDevTaxNumber>\n    </software>\n</TokenExchangeRequest>",
                    "options": {
                        "raw": {
                            "language": "xml"
                        }
                    }
                },
                "url": {
                    "raw": "https://api-test.onlineszamla.nav.gov.hu/invoiceService/v2/tokenExchange",
                    "protocol": "https",
                    "host": [
                        "api-test",
                        "onlineszamla",
                        "nav",
                        "gov",
                        "hu"
                    ],
                    "path": [
                        "invoiceService",
                        "v2",
                        "tokenExchange"
                    ]
                }
            },
            "response": []
        }
    ],
    "protocolProfileBehavior": {}
}

How should I attach the XML to the request in code?

EDIT:

The response if I take out "mode: cors" from the request header:

<html><head><meta http-equiv='content-type' content='text/html;charset=utf-8'><title>400 Bad&#x20;Request</title></head><body text=#000000 bgcolor=#ffffff><H1>400 Bad&#x20;Request</H1></BR>An&#x20;HTTP&#x20;protocol&#x20;violation&#x20;was&#x20;detected&#x20;and&#x20;your&#x20;request&#x20;was&#x20;denied&#x2E;</BR>SessionID: aZYz1fRA::02<BR>Date: 2020-03-20 09:05:33</body></html>

And the console:

Failed to load https://api-test.onlineszamla.nav.gov.hu/invoiceService/v2/tokenExchange: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9080' is therefore not allowed access. The response had HTTP status code 400. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
  • Try removing "mode: 'no-cors'" – ariel Mar 16 '20 at 05:09
  • @ariel How would that help? The server is obviously accepting my requests. The issue is with the body. – Levente Rozsenich Mar 16 '20 at 08:34
  • Have you tried? – ariel Mar 16 '20 at 16:56
  • @ariel Yes. Fails with error 400. Thank you for your contribution. – Levente Rozsenich Mar 18 '20 at 18:21
  • 1
    `no-cors` doesn't do what most people think it does. I think it will in fact drop the body. Usually you _don't_ want `no-cors` unless it's very specific circumstances. I think in your case `no-cors` will also rewrite the content-type, because `application/xml` is not allowed in `no-cors`. – Evert Mar 18 '20 at 18:46
  • Too late to edit that, but I don't think it drops the body in this case, but it _will_ drop your content-type header. – Evert Mar 18 '20 at 19:13
  • 5
    This question inspired me to write this: https://evertpot.com/no-cors/ not the first time I've seen people running into this. Not a solution to your problem, but the first step to a solution is indeed to remove `no-cors` – Evert Mar 18 '20 at 22:10
  • 1
    After that, I can probably help you get to the real answer. You will probably get a different error after removing `no-cors`, and I would like to see it. – Evert Mar 18 '20 at 22:11
  • @Evert Hi! I have updated the original post with the result. The API I am calling is open, anyone should be able to make a request with the postman collection I have posted. – Levente Rozsenich Mar 20 '20 at 08:10
  • Your postman collection only gets me a 500 response, containing `INVALID_REQUEST Érvénytelen kérés!`. I guess that’s probably because it doesn’t contain an actual token to exchange, but that doesn’t make it particularly helpful for testing either. – CBroe Mar 20 '20 at 08:21
  • @CBroe That error is generated by the server after reading the sent XML and determining that it has missing fields. I have updated the collection in the post to generate a more obvious response. Unfortunately I cannot share a request that resolves without error, because that would contain sensitive information. – Levente Rozsenich Mar 20 '20 at 13:21
  • I am still getting the exact same response as before, when testing your updated(?) collection in postman. – CBroe Mar 20 '20 at 13:44
  • @CBroe Sorry... Now it's actually updated. – Levente Rozsenich Mar 20 '20 at 13:51
  • Trying your fetch request, after removing no-cors, with _any_ body content, only gives me "Access to fetch at […] from origin […] has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource." - are you sure this endpoint is CORS-enabled in the first place …? – CBroe Mar 20 '20 at 13:56
  • The documentation only specifies the content type to send and receive, nothing else. So I am not sure. – Levente Rozsenich Mar 20 '20 at 13:59
  • I have also updated the post with the console output. – Levente Rozsenich Mar 20 '20 at 14:05
  • @CBroe if you are getting CORS related errors, that simply means now that they haven't set up CORS, and the only way you can fix this is by proxying the requests through a server you _do_ control. – Evert Mar 20 '20 at 22:11
  • @Evert I have managed to fix the problem. It was more specific to the project than I thought. This is an Electron application. I have turned off web security on the main window, and now it works properly. BUT your answer led me to discover this. If you put your answer about how no-cors can effect a http call, I will accept it as the solutioin. – Levente Rozsenich Mar 21 '20 at 16:44
  • @Evert Very nice post for misconceptions regarding CORS. – Manish Khedekar Mar 24 '20 at 07:15
  • Have you tried using request header 'Content-Type' as 'text/xml'? – Anthony McGrath Mar 25 '20 at 01:23

2 Answers2

1

First of all you have to remove no-cors, because application/xml is not allowed in no-cors. (read more)

To solve the solution you have to config (reconfig) the back-end to accept such a request. Here you can find an example for Node.js.

Alireza Mahmoudi
  • 964
  • 8
  • 35
0

I have managed to fix the problem. It was more specific to the project than I thought. This is an Electron application. I have turned off web security on the main window, and now it works properly. @Evert helped me come to this conclusion in comments.