How to POST an XML with Angular http? - javascript

I'm having trouble using JavaScript to send xml. I've tried to emulate what many others have done, but I'm not getting success. I'm getting a XML Syntax Error: Please check the XML request to see if it can be parsed. with the code 80040B19.
Here's my code. I'm trying to use the USPS Address Validation API. On page 4 of this doc, there's more info.
const apiUrl = 'http://production.shippingapis.com/ShippingAPI.dll?API=Verify';
validate(address: Object): any {
const payload = this.xmlBuilder.buildObject({
AddressValidateRequest: {
$: { USERID: 'XXXXXXXXX' }, // api key hidden
Address: {
$: { ID: '0'},
FirmName: null,
Address1: address['address2'],
Address2: address['address1'], // NOT A TYPO, they swap it
City: address['city'],
State: 'NY',
Zip5: address['postal_code'],
Zip4: null
}
}
});
console.log(payload); // SEE BELOW
const headers = new Headers({ 'Content-Type': 'text/xml' });
const options = new RequestOptions({ headers: headers });
return this.http.post(this.apiUrl, { 'XML': payload }, options)
.map((res) => {
this.parseXMLStringToObject(res.text(), (err, result) => {
console.log(result);
});
});
}
Here's what my console.log on the payload reads. I've verified this to the letter, from the order of the xml tags, to what is required tag but optional value. I'm positive the payload is correct.
<AddressValidateRequest USERID="XXXXXXXXX">
<Address ID="0">
<FirmName/>
<Address1/>
<Address2>620 Eighth Avenue</Address2>
<City>New York</City>
<State>NY</State>
<Zip5>10018</Zip5>
<Zip4/>
</Address>
</AddressValidateRequest>
One thing that I can think of is I'm somehow not using the http correctly, and I'm sending a blank xml somehow.
On their docs, they have this listed:
https://servername/ShippingAPI.dll?API=Verify&XML=……..
I noticed I'm not doing a XML in the url, but I'm assuming that when I input the Content-Type: text/xml, that it get converted. I've also tried application/xml which give the same error.

From the documentation on USPS website it seems that the call isn't a POST with the XML as payload but a GET with XML (I suppose urlencoded) in the URL XML parameter.

Related

Axios get call in Vue3 not working, although curl and javascript work as expected

I'm trying to make an API call from my Vue3 app. The prepared API has an endpoint like http://localhost:8888/api/dtconfigsearch, where one needs to pass a json payload like { "Modelname": "MyFancyModel"} to get the full dataset with the given modelname. Pure get functions without a payload / a body do work from my Vue3 project to the golang backend, but I'm having problems with passing a payload to the backend.
Test with curl -> ok
$ curl -XGET localhost:8888/api/dtconfigsearch -d '{"Modelname" : "MyFancyModel" }'
{"ID":4,"Modelname":"MyFancyModel","ModelId":"96ee6e80-8d4a-b59a-3524-ced3187ce7144000","OutputTopic":"json/fancyoutput"}
$
This is the expected output.
Test with javascript ok
Source file index.js:
const axios = require('axios');
function makeGetRequest() {
axios.get(
'http://localhost:8888/api/dtconfigsearch',
{
data: { Modelname : "MyFancyModel" },
headers: {
'Content-type' : 'application/json'
}
}
)
.then(resp => {
console.log(resp.data)
})
.catch(err => {
console.log(err)
})
}
makeGetRequest()
Output
$ node index.js
{
ID: 4,
Modelname: 'MyFancyModel',
ModelId: '96ee6e80-8d4a-b59a-3524-ced3187ce7144000',
OutputTopic: 'json/fancyoutput'
}
$
Here, I also get the desired output.
Test within Vue fails :-(
Source in the Vue one file component:
onSelection(event) {
let searchPattern = { Modelname : event.target.value }
console.log(event.target.value)
console.log("searchPattern = " + searchPattern)
axios.get("http://localhost:8888/api/dtconfigsearch",
{
data : { Modelname : "Windshield"},
headers: {
'Content-type' : 'application/json',
'Access-Control-Allow-Origin': '*'
}
})
.then(response => {
console.log(response.data)
})
.catch(err => {
console.log(err)
alert("Model with name " + event.target.value + " not found in database")
})
},
Output in browser:
In the image you can see in the terminal log on the right side that the backend is not receiving the body of the API call. However, in the browser information of the call there is content in the config.data part of the object tree, which is the payload / the body. The only thing that bothers me that it is not a json object, but stringified json, although it was entered as json object. According to the documentation, the parameter name (data) in the call should be correct to hold the body content of the api call.
I've tried different header information, looked if it could be a CORS issue, what it isn't to my opinion, exchanged key data with body, used axios instead of axios.get and adapted parameter, all without success. The version of the axios library is 0.27, identical for Vue and vanilla javascript. After checking successfully in javascript, I was sure that it would work the same way in Vue, but it didn't.
Now I'm lost and have no further ideas how to make it work. Maybe someone of you had similar issues and could give me a hint? I'd be very grateful for some tipps!!

How to get JSON in Laravel from vue.js axios POST?

I have some problem with receiving JSON data from vuex with axios in my Laravel Backend.
I have vuex store like this, and I want to send it to backend on click.
order: {
delivery_id: null,
user_id: null,
is_active: true,
bill: null,
name: null,
surname: null,
father_name: null,
phone: null,
payment_type: 'cash',
delay: null,
cashback_paid: null,
card: null,
payment_screenshot: null,
cart: null,
}
In vue component I have this method:
sendOrder() {
let order = this.$store.state.order.order;
console.log(order)
axios
.post('/api/products', order, {
header: {
'Content-Type': 'application/json'
}
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
})
}
And this is my pretty simple Laravel Controller:
$test = json_decode($request->getContent(), true);
$test = $test['payment_type'];
return response($test);
But when I'm doing this POST request, I'm receiving empty data in response.
Also, I've tried to check my API with Postman, and it's working fine. I just send request, then go to F12 > Network > find my request and copy Request Payload source data. Then I've pasted it into Postman body (raw, json) and make request with this data to same url (http://localhost:8000/api/orders), and its return 'cash' as expected. So I decided, that it's vue.js or axios problem, but I have no idea how to fix that. Thank you!
UPDATED
I already have tried to remove Content-Type from axios, JSON.stringify order and had the same result - empty data on response.
I think, before you use order in axios you should stringify the JSON data:
let order = JSON.stringify(this.$store.state.order.order);
Second part of the answer after some comments:
Are you sure about the routes file? I would call the controller from the web.php file (same folder) with a declared function (for example mytest), like this:
Route::post('/api/products', 'ProductController#mytest');
and put your controller logic in that function:
public function mytest()
{
$test = json_decode($request->getContent(), true);
$test = $test['payment_type'];
return response($test);
}
If that doesn't work (also in combination with JSON.stringify), my only idea is a typo in your "pretty simple Laravel Controller" ;)...

Angular 10 | Http post | String array append FormData

I have to make a post request to an api endpoint, but I get an error status 500.
name: "HttpErrorResponse"
ok: false
status: 500
statusText: "Internal Server Error"
This is my code:
var selectedIds = ["31"];
let sendData = new FormData();
sendData.append('auth', this.dataService.REG_AUTH);
sendData.append('identifier', identifier);
sendData.append('selected[]', selectedIds);
this.http.post<any>('APIENDPOINT', sendData).subscribe(data => {
console.log(data);
}, error => {
console.log(error);
});
The issue is in this line: sendData.append('selected[]', selectedIds); I have no clue how to pass an array to FormData.
This is a working example from our android app. I need to convert this request in angular/typescript syntax:
#JvmSuppressWildcards
#FormUrlEncoded
#POST("APIENDPOINT")
fun addData(
#Field("auth") auth: String,
#Field("identifier") identifier: String,
#Field("selected[]") selected: ArrayList<String>
): Call<ResponseBody>
What I know so far:
It seems angular does not serialize the data, so I tried some hardcoded fixes, but none of these worked:
sendData.append('selected%5B%5D', '%2231%22');
sendData.append('selected%5B%5D', '31');
sendData.append('selected%5B%5D', 31);
sendData.append('selected%5B%5D', '%5B%2231%22%5D');
sendData.append('selected%5B%5D', selectedIds);
sendData.append('selected%5B%5D', JSON.stringify(selectedIds));
If I use selected instead of selected[], then I get no error, but obviously no data is updated, so I am pretty sure it is a serialization/parsing issue.
From this answer:
FormData's append() method can only accept objects of string or blob
type. If you need to append the array, use JSON.stringify() method to
convert your array into a valid JSON string.
formData.append('selected[]', JSON.stringify(selectedIds));
The statusCode 500 is the Internal Server Error, and it's the server-side problem. So, It's better to check the API if it can receive your request or not.
FormData's append() method accept string or blob type So you can use JSON.stringify() method (formData.append('selectedIds', JSON.stringify(selectedIds));). So try this:
let selectedIds = ["31"];
let sendData = new FormData();
sendData.append('auth', this.dataService.REG_AUTH);
sendData.append('identifier', identifier);
sendData.append('selectedIds', JSON.stringify(selectedIds));
this.http.post<any>('APIENDPOINT', sendData).subscribe(data => {
console.log(data);
}, error => {
console.log(error);
});

How to upload a file along with text using fetch in react native?

I'm trying to upload a file to the server using react-native-document-picker. The problem I'm facing is I don't know how to upload the file along with a text.In my app there is a portion for file upload also there is an area for writing some text.Then it will get uploaded to the server.So I've done the following.But I'm getting this error after submitting to server
unhandled promise rejection unsupported BodyInit type
updated portion of code
filepick = () => {
DocumentPicker.show({
filetype: [DocumentPickerUtil.images()],
}, (error, res) => {
if (error == null) {
console.log(
res.uri,
res.type, // mime type
res.fileName,
res.fileSize
);
this.setState({
img_uri: res.uri,
img_type: res.type,
img_name: res.fileName
})
} else {
Alert.alert('Message', 'File uploaded failed');
}
});
};
onPressSubmit() {
const data = new FormData();
data.append('file', { uri: this.state.img_uri, type:
this.state.img_type, name: this.state.img_name })
data.append('comment', { text: this.state.text });
AsyncStorage.getItem("userdetail").then(value => {
fetch(GLOBAL.ASSN_URL +`${this.props.id}`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
'Authorization': value
},
body: data
}).then((response) => {
return response.text()
}).then((responseJson) => {
var result = responseJson;
console.log(result);
});
})
}
The function filepick() is called after choosing a file from your device.Please help me to find a solution.How do I upload this to server also how to send text without stringifying it?
body: ({
file: this.state.file,
comment: this.state.text
})
Why are you wrapping body in brackets? Removing them might fix it.
Also see this, https://github.com/facebook/react-native/issues/6025 you might want to stringify the body object, since your content type is not application/json
body: JSON.stringify({
file: this.state.file,
comment: this.state.text
})
Edit
From comments we now know the following
1) You are uploading a file separately.
2) The upload response contains information about the file
3) You are saving the entity in separate server call
4) You need to save file with that entity
The solution below assumes that you have full control over server and you are also handling the file uploading endpoint. Here is the solution
You basically do not need to upload the whole file again with your entity since it is already uploaded on server, all you need to do is to save the reference of the file with entity. Their are two ways to save the reference
1) Just save either the fileName or fileUrl in your entity table and then store the name or url with entity so it will look like this
{
id: 1,
name: 'Cat',
picture: // url or name of picture
}
2) Save the uploaded file in different table, then save the id of the file with your entity, and when you fetch entities get the related file. However if the relationship between entity and file is one to many as in one entity can have many files then you will first need to save the entity and then upload the files with reference of entity. This way your entity will look like this
{
id: 1,
name: 'Cat',
pictures: [{fileName: 'cat1'}, {fileName: 'cat2'}]
}

Seem to Have the Wrong Content Type When POSTing with Chai-HTTP

I am looking to make use of Chai-HTTP for some testing. Naturally I want to test more than my GETs however I seem to be hitting a major roadblock when attempting to make POSTs.
In an attempt to figure out why my POSTs weren't working I began hitting them against a POST test server.
Here is a POST attempt formatted using an entirely different toolchain (Jasmine-Node and Frisby) for testing (that works just fine):
frisby.create('LOGIN')
.post('http://posttestserver.com/post.php', {
grant_type:'password',
username:'helllo#world.com',
password:'password'
})
.addHeader("Token", "text/plain")
.expectStatus(200)
})
.toss();
Which results in:
Time: Mon, 27 Jun 16 13:40:54 -0700
Source ip: 204.191.154.66
Headers (Some may be inserted by server)
REQUEST_URI = /post.php
QUERY_STRING =
REQUEST_METHOD = POST
GATEWAY_INTERFACE = CGI/1.1
REMOTE_PORT = 19216
REMOTE_ADDR = 204.191.154.66
HTTP_CONNECTION = close
CONTENT_LENGTH = 64
HTTP_HOST = posttestserver.com
HTTP_TOKEN = text/plain
CONTENT_TYPE = application/x-www-form-urlencoded
UNIQUE_ID = V3GPVkBaMGUAAB1Uf04AAAAc
REQUEST_TIME_FLOAT = 1467060054.9575
REQUEST_TIME = 1467060054
Post Params:
key: 'grant_type' value: 'password'
key: 'username' value: 'hello#world.com'
key: 'password' value: 'password'
Empty post body.
Upload contains PUT data:
grant_type=password&username=hello%40world.com&password=password
And here is a POST attempt using Chai and Chai-HTTP. I would expect this to work the same as the above example using Jasmine and Frisby, however, you'll see the actual request differs in several ways.
describe('/post.php', function() {
var endPointUnderTest = '/post.php';
it('should return an auth token', function(done) {
chai.request('http://posttestserver.com')
.post(endPointUnderTest)
.set('Token', 'text/plain')
.send({
grant_type: 'password',
username: 'hello#world.com',
password: 'password'
})
.end(function(err, res) {
console.log(res);
res.should.have.status(200);
done();
});
});
});
Which results in:
Time: Tue, 28 Jun 16 06:55:50 -0700
Source ip: 204.191.154.66
Headers (Some may be inserted by server)
REQUEST_URI = /post.php
QUERY_STRING =
REQUEST_METHOD = POST
GATEWAY_INTERFACE = CGI/1.1
REMOTE_PORT = 1409
REMOTE_ADDR = 204.191.154.66
HTTP_CONNECTION = close
CONTENT_LENGTH = 76
CONTENT_TYPE = application/json
HTTP_TOKEN = text/plain
HTTP_USER_AGENT = node-superagent/2.0.0
HTTP_ACCEPT_ENCODING = gzip, deflate
HTTP_HOST = posttestserver.com
UNIQUE_ID = V3KB5kBaMGUAAErPF6IAAAAF
REQUEST_TIME_FLOAT = 1467122150.9125
REQUEST_TIME = 1467122150
No Post Params.
== Begin post body ==
{"grant_type":"password","username":"hello#world.com","password":"password"}
== End post body ==
Upload contains PUT data:
{"grant_type":"password","username":"hello#world.com","password":"password"}
Notice the difference in CONTENT_TYPE, Post Params and PUT data in particular (I think this is the source of my problem).
Where Jasmine/Frisby would submit the POST using the 'application/x-www-form-urlencoded' format, Chai-HTTP seems to be using the 'application/json' format.
Am I somehow misusing Chai-HTTP's POST capabilities? Or does Chai-HTTP not allow for 'application/x-www-form-urlencoded' POST requests? I do not seem to be able to resolve this and it is the final hurdle for me to jump to make the transition to using a Mocha/Chai toolchain for my testing (which is the goal, I would prefer to not use a different library unless it's absolutely necessary).
Having discussed this further on Chai-HTTP's Git-Hub page, I was able to find out that this is expected behaviour of SuperAgent, the HTTP request library under the hood of Chai-HTTP, which auto-detects the content-type based on what kind of data is contained in the .send() call.
I stumbled across this particular question as well which helped clarify what the difference between content-types actually was.
If anyone else runs into this problem, I've learned that Chai-HTTP's POST requests can be altered quite easily (kudos to meeber's help here) using calls like this:
//Override auto-detection by specifying the header explicitly
.set('content-type', 'application/x-www-form-urlencoded')
//Select the type 'form'
.type('form')
//Pass multiple strings in send instead of using an object
.send('grant_type=password')
.send('username=hello#world.com')
.send('password=password')
Creating a request that looks like this:
describe('/post.php', function() {
var endPointUnderTest = '/post.php';
it('should return an auth token', function(done) {
chai.request('http://posttestserver.com')
.post(endPointUnderTest)
.set('Token', 'text/plain')
.set('content-type', 'application/x-www-form-urlencoded')
.type('form')
.send('grant_type=password')
.send('username=hello#world.com')
.send('password=password')
.end(function(err, res) {
console.log(res);
res.should.have.status(200);
done();
});
});
});

Categories

Resources