Shopify integration: trouble on making authenticated requests - json

Sorry for cross posting this issue here in SO
So I follow the "https://docs.shopify.com/api/authentication/oauth"; guide and successfully proceed to "Making authenticated requests" part, then I stuck at there. Here is my code (in Java):
String payload = "{\"script_tag\":{\"src\":\"http:\\/\\/localhost:8080\\/js\\/shopify.js\",\"event\":\"onload\"}}";
String url = "https://pixolut-shopify-test.myshopify.com/admin/script_tags.json";
HttpPost post = new HttpPost(url);
post.setHeader("X-Shopify-Access-Token", accessToken);
post.setEntity(new StringEntity(payload, ContentType.APPLICATION_JSON));
HttpResponse resp = HttpClientBuilder.create().build().execute(post);
StatusLine statusLine = resp.getStatusLine();
if (statusLine.getStatusCode() != 200) {
throw new RuntimeException("Error inject script tag: %s", statusLine.getReasonPhrase());
}
I am using apache httpclient (v4.3.1) to post my request to Shopify. The problem I've found is I always get HTTP/1.1 422 Unprocessable Entity, I don't know where I am wrong.
If I use postman to test with exactly the same payload, url and access token, I get the following response:
{
"errors": {
"script_tag": "Required parameter missing or invalid"
}
}
Anyone can help?
Update
I got content of the 422 response:
{"errors":{"src":["is invalid"]}}

I had the same problem, using curl. The missing ingredient was setting the Content-Type for the request:
curl -H "X-Shopify-Access-Token: {token}" -H "Content-Type: application/json" -d "{\"script_tag\":{\"event\":\"onload\",\"src\":\"{script_uri}\"}}" https://{shop}.myshopify.com/admin/script_tags.json
You should be able to do the same with Postman: https://www.getpostman.com/docs/requests#headers

I got a similar error running the shopify api natively without a wrapper.
I ended up using a node module that helped. I know you're writing in Java so not sure if they have a similar wrapper.
It might help to take a look at how they implement pinging the shopify api in node.
https://github.com/christophergregory/shopify-node-api

Related

How do I make a secure API request from an Arduino ESP32, programmed in the Arduino IDE using ArduinoJson?

I have been hacking away at this for a few days with no luck.
I am trying to make a secure (SSL/HTTPS) API request in an Arduino environment. The controller I am using is an ESP32, which connects through wifi fine, and can retrieve/post data. However I am having no luck connecting to a secure API.
I'm trying to connect to this API https://strike.acinq.co/documentation/api-reference
EXAMPLE CURL REQUEST IN API'S DOCUMENTATION:
$ curl https://api.dev.strike.acinq.co/api/v1/charges \
-u sk_pJDwxFxCVw5fQJhRRMpf29jReUjjN: \
-X POST \
-d amount=42000 \
-d currency="btc" \
-d description="1%20Blockaccino"
Here is my Arduino code, I am using the ArduinoJson.h and WiFi.h libraries:
// Connect to HTTP server
WiFiClient client;
client.setTimeout(10000);
if (!client.connect("api.strike.acinq.co", 80)) {
Serial.println(F("Connection failed"));
return;
}
Serial.println(F("Connected!"));
// Send HTTP request
client.println(F("GET /api/v1/charges?id=MYKEY&amount=4200&currency=btc HTTP/1.0"));
client.println(F("Host: api.strike.acinq.co"));
client.println(F("Content-Type: application/x-www-form-urlencoded"));
client.println(F("Connection: close"));
if (client.println() == 0) {
Serial.println(F("Failed to send request"));
return;
}
// Check HTTP status
char status[32] = {0};
client.readBytesUntil('\r', status, sizeof(status));
if (strcmp(status, "HTTP/1.1 200 OK") != 0) {
Serial.print(F("Unexpected response: "));
Serial.println(status);
return;
}
A 401 "Invalid API Key" Is the closest I have got. I know the API-key works, and that I am just using it wrong. I've tried moving the key to:
client.println(F("id: MYKEY"));
but that didn't work either.
I have tried other libraries and ArduinoJson seems to be the best. I think the issue is the fact its a secure server and the layout of my request. I found many resources for connecting to open API's on Arduino, but nothing on connecting to secure ones. I think I am almost there with the code...
UPDATE
So I have updated my code. I am still trying to use ArduinoJson. I can connect to the API but it keeps spitting out "HTTP/1.1 400 BAD_REQUEST". I don't know weather this is because its over HTTPS or the formatting of my request.
In the API docs -u and -X don't have a field name like "amount=4200", so I am assuming -u would just be added client.print("?="+apiKey);
//open weather map api key
String apiKey= "myapikey";
int status = WL_IDLE_STATUS;
char server[] = "api.strike.acinq.co";
Serial.println("\nStarting connection to server...");
// if you get a connection, report back via serial:
if (client.connect(server, 80)) {
Serial.println("connected to server");
// Make a HTTP request:
client.print("POST /api/v1/charges");
client.print("?="+apiKey);
client.print("&amount=4200");
client.print("&currency='btc'");
client.println("&description='sweets'");
client.println("Host: api.strike.acinq.co");
client.println("Connection: close");
client.println();
}
else {
Serial.println("unable to connect");
}
UPDATE
I figured out the println and print actually mean something and have subsequently organised my request much better. It still comes back with 400 Unauthorized?
String PostData = "&description=\"car\"&amount=1000&currency=\"sweetsandthat\"";
client.println("POST /api/v1/charges HTTP/1.1");
client.println("Host: api.strike.acinq.co");
client.println("Authorization: Basic "+apiKey);
client.print("Content-Length: ");
client.println(PostData.length());
client.println(); // blank line required
client.println(PostData);
Serial.println("POSTED DATA: " + PostData);
// client.stop();
client.println();
} else {
Serial.println("unable to connect");
}
delay(1000);
String line = "";
while (client.connected()) {
line = client.readStringUntil('999');
Serial.println(line);
Serial.println("parsingValues");
//create a json buffer where to store the json data
StaticJsonBuffer<5000> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(line);
if (!root.success()) {
Serial.println("parseObject() failed");
return;
}
//get the data from the json tree
String nextWeatherTime0 = root["id"][0];
// Print values.
Serial.println(nextWeatherTime0);
}
client.println("Connection: close");
client.stop();
}
Check the response for a BAD request, We usually get it when we deal with a bad URL or URL not found. check whether you are connecting to the same url mentioned in docs.
First connect to the api and after that make queries like providing your api key and feilds
remove this.
client.println("Host: api.strike.acinq.co");
and use GET request to get the response of the data you have in these fields
String PostData = "&description=\"car\"&amount=1000&currency=\"sweetsandthat\""
I have also been struggling to get an https post to work on the esp32. A few things, the wifi.h module, I believe, does not support https. The WiFiClientSecure.h does, and you need to set the port to 443. I have also failed to get a POST to work, but I succeed in a basic GET test connection to howsmysssl.com. Andreas Spiess covers this well in a youtube video. He goes beyond SSL to establishing trust. I just want basic SSL to work, so if you get this figured out, please let me know. Hopefully I got you one step closer. :)

Node-red - Posting data to influxdb via http

Im trying to post data to an Influxdb via Node-red.
Via CURL i can post this:
curl -i -XPOST 'http://localhost:8086/write?db=waterlevel' --data-binary 'vattenstand,lake=siljan,region=dalarna value=160.80'
and it puts data to InfluxDb.
When I try to post via Node-red and an HTTP request I get the error:
{"error":"unable to parse '{\"url\":\"http://192.168.1.116:8086/write?db=waterlevel\",\"method\":\"POST\",\"body\":\"vattenstand,lake=siljan,region=dalarna value=160.80\",}': missing tag value"}
I use this code in a function in Node-red and pass it to the HTTP request:
var dataString = 'vattenstand,lake=siljan,region=dalarna value=160.80';
msg.payload = {
'url': 'http://192.168.1.116:8086/write?db=waterlevel',
'method': 'POST',
'body': dataString,
};
msg.headers = {
Accept: "application/json"
};
return msg;
The sidebar help for the node details the msg properties you should be setting to configure the node.
You are passing in URL, method and body as properties of msg.payload. That is not correct.
They should be set as msg.url, msg.method for the first two, and msg.payload should be the body of the request.
In this instance, you have already configured the node with a URL and method directly, so there's no need to pass them in with the message. In fact, as you have configured the URL in the node you will find you cannot override it with msg.url. if you want to set the URL with each message, you must leave the node's URL field blank in the editor.
You may also need to set the content-type header.
Assuming you are happy to leave the URL and method hard coded in the node, you function should be something like:
msg.payload = 'vattenstand,lake=siljan,region=dalarna value=160.80';
msg.headers = {
Accept: "application/json"
};
msg.headers['Content-type'] = 'application/x-www-form-urlencoded';
return msg;
Why don't you use the spezial influxdb node?
https://flows.nodered.org/node/node-red-contrib-influxdb
Advantage: The http header need not be created. You can reuse the defined connection for other data.

Not able to capture previous API response and append the response in URL of Post Request API

I am trying to POST API request where I am getting API response as
"d": {
"__metadata": {
"uri": "http://ev-qa02.zs.local/IncentiveManager/0002i1/wcf/v5.svc/InDataRequestCreators('9f31c6da-ec56-4360-8589-d21b6320f99b')",
"type": "ZSAssociates.Javelin.ETL.Rest.v5.InDataRequestCreator"
},
"ScenarioId": "9f31c6da-ec56-4360-8589-d21b6320f99b",
"CallbackUrl": "",
"DataExpiresOnUtc": "/Date(4103913600000)/",
"CreateScenarioIfMissing": false,
"AdapterId": "0fcbd8d2-f5cb-4e2a-bda8-bb37037b022d",
"InDataRequestIdOut": "eb36f8a9-5b7d-4835-88f6-4af67830c1e9",
"InDataRequestUrlOut": "/InDataRequests('eb36f8a9-5b7d-4835-88f6-4af67830c1e9')"
}
}
Now I am trying to hit another API request where my URL would be kind of
http://ev-qa02.zs.local/IncentiveManager/0002i1/WCF/V5.svc/InDataRequests('eb36f8a9-5b7d-4835-88f6-4af67830c1e9')/FileCreator
*InDataRequests('eb36f8a9-5b7d-4835-88f6-4af67830c1e9') This random number is generated from above response value "InDataRequestIdOut"
How can I append the URL taking previous API response and adding in my 2nd POST request.
I am not able to capture my response and used it in other API POST request? i would realy appreciate if you can help me here,been stuck in this issue since couple of days,I went through doc and examples too but couldn't resolve this.I have attached screenshot too.PostUrlFailureScreenshot
My main problem is line number 26 and 27 from eclipe screenshot
Scenario: Verify that JIM Idr request ofr Post
Given header Content-Type = 'Application/JSON'
And header Accept = 'Application/JSON'
And header Authorization = 'Basic
UUEwMl9JbmNlbnRpdmVNYW5hZ2VyXzAwMDJpMTpZWkxaRjlGclR1eWhlcVNJbXlkTlBR'
Given path 'InDataRequestCreators'
* def user =
"""
{
"ScenarioId":"9f31c6da-ec56-4360-8589-d21b6320f99b",
"AdapterId":"0fcbd8d2-f5cb-4e2a-bda8-bb37037b022d",
"DataExpiresOnUtc":"2100-01-18T00:00:00",
"CreateScenarioIfMissing":"false"
}
"""
And request user
When method post
Then status 201
* print 'the value of response is:', response
And def app = response
And path 'app.InDataRequestIdOut' + '/FileCreators'
* def body =
"""
{
"InDataRequestId": "1d6326a2-d25f-41d2-9303-8a6e6101efcc",
"ProcedureName": "",
"SourceWorkspacePath": ""
}
"""
And request body
When method post
Then status 201
First, it looks to me you are using the wrong Eclipse plugin for Cucumber, please refer to this issue and make sure: https://github.com/intuit/karate/issues/90
There are so many things you are doing wrong. For example it should be application/json (lowercase). There are many places you are mixing upper case and lower case in your above description, please take care.
And there is no way to understand how the URL is being set up, without this - I can't provide proper help.
You have a fundamental misunderstanding of how to use Karate expressions, for example this is just concatenating two strings:
And path 'app.InDataRequestIdOut' + '/FileCreators'
This may give you some hints, instead of the above:
When url baseUrl
And path "InDataRequests('" + response.InDataRequestIdOut + "')/FileCreator"
And is it FileCreator or FileCreators. You seem to be quite careless :(

Hitting endpoint GET of HTTP REST API, shows "Invalid User"

I am hitting endpoint GET of HTTP REST API, http://tw-http-hunt-api-1062625224.us-east-2.elb.amazonaws.com/challenge
It says "For every API call, pass your UserID as an HTTP header with key 'userId'."
So I am doing http://tw-http-hunt-api-1062625224.us-east-2.elb.amazonaws.com/challenge/userId/xxxx
But it shows:[Invalid User!]
What I am doing wrong?
You need to pass the userId in HTTP headers, not in path. Below is the CURL equivalent:
curl -X GET http://tw-http-hunt-api-1062625224.us-east-2.elb.amazonaws.com/challenge -H 'userId: test'
You need to send similar request from your client.
Pretty Simple,
You need to pass HTTP Header with the key as "userId" and value as "WHATEVER_USERNAME_YOU_ARE_GIVEN"
[NOTE: I'm sharing in the context of a Java Code]
Something like this,
private static HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.add(USER_ID_HEADER, USER_ID);
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
Here,
USER_ID_HEADER = "userId" and
USER_ID = "USERNAME_I_WISH_TO_PASS"
Please let me know if you still struggle finding the solution.

Meteor iron:router prepare request.body when JSON

Currently I play around with iron:router's solution for a restful API. For this I use the .put, .get ... methods which are iron:router has implemented.
This is my example I work with:
Router.route('/api', {where:'server'})
.put(function(){
var req;
req = this.request;
console.log(req.body);
this.response.end('PUT finished.');
});
When I execute the following I will get the expected response (PUT finished):
curl -XPUT "http://localhost:4000/api " -d'{"name": "timo"}'
But the console.log(req.body) returns a strange value converted to an object.
The returned value is:
{
'{"name": "timo"}\n' : ''
}
It seems that iron:router trys to convert the body into an object but did not recognized that the given request string is a valid JSON string.
Is there smth I did wrong ? I did not find anything helpful yet to prepare iron:router that the given request body is still JSON.
Maybe its a better solution not to tell iron:router that the given request is a JSON and instead to tell iron:router that it shouldn't do anything so I can convert the JSON string by myself ?
You didn't specify the content type in your curl request. Try this instead:
curl -XPUT "http://localhost:4000/api " -d'{"name": "timo"}' -H "content-type: application/json"
With that it works for me:
I20150522-09:59:08.527(-7)? Request { name: 'timo' }
(and without it doesn't).