I need to pass the following json to this function so Shopify Api can understand the submission. I am unable to create the correct variable format and pass it to server.Shopify API is expecting the following json to be passed via POST
Replace REQUEST_URL with your API URL
Replace JSON_STRING with your actual json string
var request = URLRequest(url: URL(string: "REQUEST_URL")!)
request.httpMethod = "POST"
let postString = "JSON_STRING"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
}
task.resume()
convert your object into dictionary and then serialize it by
do{
let data = try JSONSerialization.data(withJSONObject: dict, options: [])
postString = String.init(data: data, encoding: String.Encoding.utf8)!
}catch{
print(error)
}
Related
I am attempting to do this: Insert a http validation token into serialized JSON data. I already have working the ability to pass it normally in JSON and also to pass it in a header using a custom authorization extension. What I would like to do is, in the validator, if the request isn't in the header data or in the form data, deserialize the passed data and look in there. I can't actually find the data in the request though. When I read the passed data (84 bytes), i just ended up with a bunch of numbers.
Here's the validator for antiforgery:
namespace DispatchCrude.Extensions
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,
AllowMultiple = false, Inherited = true)]
public sealed class ValidateHeaderAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
var httpContext = filterContext.HttpContext;
var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
//try header first
var token = httpContext.Request.Headers["__RequestVerificationToken"];
//try normal method
if (token == null)
{
for(int cl = 0; cl < httpContext.Request.Form.Keys.Count; cl++)
{
if (httpContext.Request.Form.Keys[cl] == "__RequestVerificationToken")
{
token = httpContext.Request.Form[httpContext.Request.Form.Keys[cl]];
}
}
}
if (token == null)
{
//this section isn't finding the passed data
//get here if form stringified
System.IO.Stream str; String strmContents;
Int32 counter, strLen, strRead;
// Create a Stream object.
str = httpContext.Request.InputStream;
// Find number of bytes in stream.
strLen = Convert.ToInt32(str.Length);
// Create a byte array.
byte[] strArr = new byte[strLen];
// Read stream into byte array.
strRead = str.Read(strArr, 0, strLen);
// Convert byte array to a text string.
strmContents = "";
for (counter = 0; counter < strLen; counter++)
{
strmContents = strmContents + strArr[counter].ToString();
}
token = strmContents; //just so i can debug the returned token
}
//if both fail, attempt to check stringified data for matching token.
AntiForgery.Validate(cookie != null ? cookie.Value : null, token);
}
}
}
and here's some example code we are serializing the form data:
$.ajax({
type: "POST",
headers: appendVerificationToken(),
url: "/OrderSettlement/SessionApplyRatesCancel",
data: JSON.stringify({ key: data.key }),
contentType: "application/json",
success: function () {
/* decided to NOT close the window (just cancel and show the [CANCELLED] description)
// on success, close the owning popup
runFuncByNameSingleParameter(_owningPopup.Close);
*/
}
});
As I said, passing it in the header works, but I would like to be able to add it to the data instead and I can't find it in the request to parse it.
thanks to Ouroborus, I was able to come up with a solution.
This works:
string json;
var position = httpContext.Request.InputStream.Position;
using (var reader = new StreamReader(httpContext.Request.InputStream, Encoding.UTF8, false, 8192, true))
{
json = reader.ReadToEnd();
//you MUST reset the input stream to start or you will break post.
httpContext.Request.InputStream.Seek(position, SeekOrigin.Begin);
try
{
var jsonObj = Json.Decode(json); //attempt to parse into json object.
token = jsonObj["__RequestVerificationToken"];
}
catch
{
//eat the parse errors. That simply means it's not json.
}
}
I hope it helps someone else. Note that you must reset the stream back to zero, exactly how I'm doing it, or the controller function won't receive any passed data.
PasteBin JSON
I would like to get this as Object it says jsonlint is valid but parsing is not anyone help would appreciate
"Data":[{...},{...},] // structure build like this
when i try
JSON.parse(jsonparamter) <-- Uncaught SyntaxError: Unexpected token A in JSON at position 71
at JSON.parse (<anonymous>)
at <anonymous>:1:6
There are multiple levels of JSON encoded data so you will have to create a loop to decode the elements deeper in the JSON nest. Use the below code to see an example of accessing Data.Adress.Value in this dictionary
// set up urls and headers for making HTTP req
corsurl = 'https://cors-anywhere.herokuapp.com/'
jsonurl = 'https://pastebin.com/raw/vuecweML'
headerNames = ['Content-Type','Accept']
headerValues = [ 'application/json', 'application/json']
// Modular get request function that I use
function getRequest (baseRestURL, APIPath, headerNames, headerValues, callback) {
var completeRestURL = baseRestURL + APIPath
console.log('REST API URL: ' + completeRestURL)
var method = 'GET'
var url = completeRestURL
var async = true
var request2 = new XMLHttpRequest()
request2.onload = function () {
console.log('ONLOAD')
var status = request2.status // HTTP response status, e.g., 200 for "200 OK"
console.log(status)
console.log(request2.responseText)
var response = request2.responseText
return callback(response)
}
request2.open(method, url, async)
for (var i in headerNames) {
request2.setRequestHeader(headerNames[i], headerValues[i])
}
request2.send(null)
}
// Our code of interest
getRequest(corsurl, jsonurl, headerNames, headerValues, response => {
parsed = JSON.parse(response).Data //parse our data the first time, and get the data attribute from dictionary
objects = JSON.parse(parsed) // parse a second time ( as data is JSON encoded twice )
selection = JSON.parse(objects[0].Address)[0].Value // parse a third time and select an attribute
document.getElementById('result').innerHTML = selection // Add it to our html to display
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<div id='result'> Loading </div>
I have an array in javascript that I am trying to pass to my mobilefirst java adapter. I call my adapter like so,
myArr = [1,2,3];
var sendPost = new WLResourceRequest(
"/adapters/MyAdpater/path",
WLResourceRequest.POST
);
var formParam = {"arr":myArr};
sendTicketPost.sendFormParameters(formParams);
Then in my adapter I can have my method and get the param
public JSONObject postAdapterFx(#FormParam("arr") List<Integer> myArray) {}
Currently when I send this I just get a 400 error and it is because the adapter doesnt like the form param as that type, so what else could I set myArray to in the adapter? I can send it as a string and then convert the string to a List<Integer> in the java but that is really messy and I would like to avoid doing that.
So how can I pass this array?
Thanks for the help
you can do it in body with request.send(yourArray). Then you can read it in Java with buffer.
Example from knowledge center
var request = WLResourceRequest(url, method, timeout);
request.send(json).then(
function(response) {
// success flow
},
function(error) {
// fail flow
}
);
You will need to take an extra step before sending the form data to the adapter. sendFormParameters only accepts objects with simple values i.e., string, integer, and boolean; in your case arr is an array.
Create a utility function that will encode the form data, you can use the following:
function encodeFormData(data) {
var encoded = '';
for(var key in data) {
var value = data[key];
if(value instanceof Array) {
encoded += encodeURI(key+'='+value.join('&'+key+'='));
} else {
encoded += encodeURI(key+'='+value);
}
encoded += '&';
}
return encoded.slice(0, -1);
}
Then you will need to update your code as follows:
var myArr = [9,2,3];
var sendPost = new WLResourceRequest("/adapters/Cool/users/cool", WLResourceRequest.POST);
var formParam = {"arr" : myArr};
sendPost.sendFormParameters(encodeFormData(formParam));
I'm having a problem when signing an OAuth request that contains an array in the URL parameters.
Here's an example of a URL i want to sign:
http://example.com/oauth1/products?filter[categorie]=myCategorie&page=1
I'm using OAuthSignatureJS to generate the signature, and it works perfectly when passing simple parameters but when adding an array is returns an Invalid Signature response.
I tried using a JSON instead of url but still the same, and i can't change the API server code.
This is the calling function(AngularJS)
var request = generateRequest('GET', 'products', page, 'myCategorie');
request = request+'&page='+page+'&filter[categorie]=myCategorie';
$http.get(request, {timeout: config.timeout})
.success(function(json, status, headers, config){
})
.error(function(error){
console.log(error);
})
And this is the function i use to generate the request
var generateRequest = function(method, route, page = null, categorie = null) {
var timestamp = Math.floor(new Date().getTime()/1000);
var nonce = generateNonce();
var parameters = {
oauth_consumer_key: api.key,
oauth_nonce: nonce,
oauth_timestamp: timestamp,
oauth_signature_method: api.signature,
oauth_version: api.version
};
if(page) parameters.page = page;
if(categorie) {
parameters.filter = [];
parameters.filter['categorie'] = categorie;
console.log(parameters);
}
var link = 'http://example.com/oauth1/' + route;
// Generating the signature with OauthSignatureJS
var signature = oauthSignature.generate(method, link, parameters, api.secret);
var authentification = '?oauth_consumer_key='+api.key+'&oauth_signature_method='+api.signature+'&oauth_version='+api.version+'&oauth_timestamp='+timestamp+'&oauth_nonce='+nonce+'&oauth_signature='+signature;
return link+authentification;
}
When passing the filter[categorie] parameter in the URL, the server respond with a 401 Unauthorized message.
Invalid Signature - provided signature does not match
Is there something wrong with my code or is it the OauthSignature JS library ?
Thanks in advance.
I found an answer, i just needed to add the filter array as a string to the parameters object parameters['filter[categorie]'] = categorie;
So this is the new working code
var generateRequest = function(method, route, page = null, categorie = null) {
var timestamp = Math.floor(new Date().getTime()/1000);
var nonce = generateNonce();
var parameters = {
oauth_consumer_key: api.key,
oauth_nonce: nonce,
oauth_timestamp: timestamp,
oauth_signature_method: api.signature,
oauth_version: api.version
};
if(page) parameters.page = page;
if(categorie) parameters['filter[categorie]'] = categorie;
var link = 'http://example.com/oauth1/' + route;
// Generating the signature with OauthSignatureJS
var signature = oauthSignature.generate(method, link, parameters, api.secret);
var authentification = '?oauth_consumer_key='+api.key+'&oauth_signature_method='+api.signature+'&oauth_version='+api.version+'&oauth_timestamp='+timestamp+'&oauth_nonce='+nonce+'&oauth_signature='+signature;
return link+authentification;
}
Have tried many options to update a product in ECWID using Google Apps Script UrlFetchApp.fetch() put method but not succeeded. Following are the different ways that I've written the code and tested, but am getting different type of errors.
I guess, am missing some small thing, which am not able to figure it out. Please help me to fix this issue.
API: ECWID Products API (http://kb.ecwid.com/w/page/25285101/Product%20API#RESTAPIMethodupdateaproduct)
Method: PUT (to update the product details)
Sample Code 1:-
function updateProducts(){
var products_authkey = "xxxxxxxx";
try{
var url ="https://app.ecwid.com/api/v1/xxxxx/product?id=xxxxxxxx&secure_auth_key="+products_authkey;
var payload = {price:62755};
var options ={method:"put",ContentType:"application/json",payload:payload};
var result = UrlFetchApp.fetch(url, options);
var response = result.getContentText();
}catch(e){
Browser.msgBox(e);
}
}
Error:-
"{ "error": "OTHER", "errorMessage": "Error parsing JSON: A JSONObject text must begin with '{' at character 0" }"
Version 2:-
Tried converting the object to json stringify, but the same error.
function updateProducts_version2(){
try{
var url ="https://app.ecwid.com/api/v1/xxxx/product?id=xxxxx&secure_auth_key="+products_authkey;
var payload = {price:62755};
var payload_json = Utilities.jsonStringify(payload);
var options ={method:"put",ContentType:"application/json",payload:payload_json,muteHttpExceptions:true};
var result = UrlFetchApp.fetch(url, options);
var response = result.getContentText();
var res_code = result.getResponseCode();
var x = 1;
}catch(e){
Browser.msgBox(e);
}
}
Error:-
"{ "error": "OTHER", "errorMessage": "Error parsing JSON: A JSONObject text must begin with '{' at character 0" }"
Version 3:- (Tried passing secure_auth_key using Authorization in headers)
function updateProducts_version3(){
try{
var url ="https://app.ecwid.com/api/v1/xxxxx/product?id=xxxxx";
var payload = {price:62755};
var headers = {Authorization: 'xxxxxxx'};
var options = {headers:headers,method:"put",ContentType:"application/json",payload:payload};
var options ={method:"put",ContentType:"application/json",payload:payload,muteHttpExceptions:true};
var result = UrlFetchApp.fetch(url, options);
var response = result.getContentText();
var res_code = result.getResponseCode();
var x = 1;
}catch(e){
Browser.msgBox(e);
}
}
Error:-
{ "error": "OTHER", "errorMessage": "API key not found in request parameters" }
Also to note that, I've tried using DevHttpClient chrome plugin, it's updating properly.
Which means that there's some problem the way we're using UrlFetch. Please help me in fixing this issue...
Thanks in advance...
Credentials are needed to test this, so that's up to you. You probably need to both stringify & encode the payload. You also had incorrect capitalization on contentType, which you could check with UrlFetchApp.getRequest().
function updateProducts_version2a(){
try{
var url ="https://app.ecwid.com/api/v1/xxxx/product?id=xxxxx&secure_auth_key="+products_authkey;
var payload = {price:62755};
var payload_json = encodeURIComponent(JSON.stringify(payload));
var options ={method:"put",contentType:"application/json",payload:payload_json,muteHttpExceptions:true};
var result = UrlFetchApp.fetch(url, options);
var response = result.getContentText();
var res_code = result.getResponseCode();
var x = 1;
}catch(e){
Browser.msgBox(e);
}
}
This next version seemed to work - by suppressing the price change and using a store's ID, it mimicked a product 'get', according to the docs you referenced. This time, the error message might be indicating some level of success: "This Ecwid account doesn't have access to Ecwid API. Please, consider upgrading it."
You'll notice that the URL has been separated out, with the basic header info of product ID and auth key together.
function updateProducts_version4(){
try{
var url ="https://app.ecwid.com/api/v1/xxxx/product";
var payload = encodeURIComponent(JSON.stringify({
price:62755
}));
var headers = {id:'xxxx',
secure_auth_key: 'xxxxxxx'
};
var options = {
headers:headers,
method:"put",
contentType:"application/json",
muteHttpExceptions:true,
payload:payload
};
var request = UrlFetchApp.getRequest(url, options); // Debug: check what would be fetched
var result = UrlFetchApp.fetch(url, options);
var response = result.getContentText();
var res_code = result.getResponseCode();
var respHeaders = result.getHeaders(); ///
debugger;
}catch(e){
Logger.log(e);
//Browser.msgBox(e);
}
}
Without your creds, that's as far as I can take it... tell us how that works for you.