I was able to make a graphql POST from Postman by choosing "GraphQL" content type:
When I am trying to perform the POST from C#:
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
var myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
myHttpWebRequest.Method = "POST";
myHttpWebRequest.ContentType = "application/graphql";
myHttpWebRequest.Headers.Add("Authorization", authToken);
var encoding = new ASCIIEncoding();
byte[] byte1 = encoding.GetBytes(postData);
myHttpWebRequest.ContentLength = byte1.Length;
var newStream = myHttpWebRequest.GetRequestStream();
newStream.Write(byte1, 0, byte1.Length);
using (var response = (HttpWebResponse)myHttpWebRequest.GetResponse())
{
using (var receiveStream = response.GetResponseStream())
{
using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8))
{
string strContent = readStream.ReadToEnd();
return strContent;
}
}
}
it looks the the content type is expected to be application/json even I specifically set content type to be "application/graphql" because the response I get is:
{"data":null,"errors":[{"message":"failed to recognize JSON request: 'invalid character 'q' looking for beginning of value'","path":null,"extensions":{"timestamp":"2021-05-19T16:04:23.091659509Z"}}]}
How can I rewrite this part as json?
query{
viewer{
accounts(filter: {accountTag: "accountTagHere"}){
ipFlows1mGroups(
limit:10
filter: {datetimeMinute_gt: "2021-05-19T16:00:00Z"}){
avg{bitsPerSecond}
}
}
}
}
This doens't work:
var postParams = #"{`query`:`viewer{accounts(filter: { accountTag: ...";
postParams = postParams.Replace("`", "\"");
If you use application/graphql, according to the original guidelines from Facebook here, the body of the POST should be the query and only the query, just as you've got in your Postman screenshot. You shouldn't need to encode it, just set the body using StringContent (assuming you're using HttpClient).
Another option though is to POST using application/json and then you need to post JSON of the form as shown on that page and below. (Note: make sure to use an operationName that matches the one in the query, or just not pass it if you've got only one and it's not named)
{
"query": "...",
"operationName": "...",
"variables": { "myVariable": "someValue", ... }
}
Finally, why not use a library that makes this easier for you? There's options for GraphQL C# client's.
StrawberryShake - Generates typed clients from .graphql files and can have a store backing it (think redux) that caches/syncs data, supports reactive concepts, etc. More here. There's even a VS extension that gives you intellisense when writing your queries.
graphql-dotnet/graphql-client - A simple wrapper around HttpClient
Related
I have an api
http://cbastest.cadvilpos.com/module/posmodule/customapi
with parameters
{
"action":4,
"device_token": "3e8ea119a90ee6d2",
"key":"9475962085b3a1b8c475d52.95782804",
"shop":1,
"language":1
}
This is working fine in postman. But when I try to connect from c# project its showing an error {"success":0,"error":"Missing the action parameter."}. Please give a working C# code to get the json result.
The code I tried:
var request = (HttpWebRequest)WebRequest.Create("http://cbastest.cadvilpos.com/module/posmodule/customapi");
var postData = "{ 'action':'4', 'device_token':'3e8ea119a90ee6d2','key':'9475962085b3a1b8c475d52.95782804','shop':'1','language':'1'}";
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response2 = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response2.GetResponseStream()).ReadToEnd();
You don't need to use a raw HttpWebRequest object to make an HTTP call. HttpClient was introduced in 2012 to allow easy asynchronous HTTP calls.
You could do something as simple as :
var content=new StringContent(postData,Encoding.UTF8, "application/json");
HttpResponseMessage response=await httpClient.PostAsync(url,content);
//Now process the response
if (response.IsSuccessCode)
{
var body=await response.Content.ReadAsStringAsync();
var responseDTO=JsonConvert.DeserializeObject<MyDTO>(body);
}
Instead of building a JSON string by hand you could use a strongly typed class or an anonymous object and serialize it to JSON with JSON.NET :
var data=new {
action=4,
device_token="3e8ea119a90ee6d2",
key = "9475962085b3a1b8c475d52.95782804",
shop=1,
language=1
};
var postData=JsonConvert.SerializeObject(data);
var content=new StringContent(postData,Encoding.UTF8, "application/json");
var response=await httpClient.PostAsync(url,content);
...
You can read a response body in one go as a string, using ReadAsStringAsync or you can get the response stream with ReadAsStreamAsync. You could copy the response data directly to another stream, eg a file or memory stream with HttpContent.CopyToAsync
Check Call a Web API from a .NET Client for more examples. Despite the title, the examples work to call any HTTP/REST API.
The Microsoft.AspNet.WebApi.Client package mentioned in that article is another thing that applies to any call, not just calls to ASP.NET Web API. The extension method PostAsJsonAsync for example, combines serializing and posting a request to a url. Using it, posting the action DTO could be reduced to a single line:
var data=new {
action=4,
device_token="3e8ea119a90ee6d2",
key = "9475962085b3a1b8c475d52.95782804",
shop=1,
language=1
};
var response=await httpClient.PostAsJsonAsync(url,data);
There is a button in Postman that will generate code for the currently defined request. The link is here:
And this is what the code looks like. You'll need to pull in RestSharp from Nuget
I have been wasting few days on this issue already...
The main problem is - I dont know how to POST data.
I would like to start by getting OrderReferenceDetails.
by looking at MWS Scratchpad (API Section: Off Amazon payments, Operation: GetOferenceDetails).
As I understand, first thing I should do, is to calculate signature. So by using this Amazon developer guide, and taking values in example in scratchpad, I created string, from which I calculated signature. This string looks like this
POST
mws.amazonservices.com
/offamazonpayments_sandbox/2013-01-01
Action=GetOrderReferenceDetails&AmazonOrderReferenceId=[_my order reference id_]&AWSAccessKeyId=[_my access key_]&SellerId=[_my seller id_]&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2014-11-04T12%3a15%3a38.1988397Z&Version=2013-01-01
So I hash this and get a signature, then I should add it to line of query parameters like &Signature=[_my clalculated signature]
Function I use to calculate signature:
private static String sign(String data, String secretKey)
{
String result = null;
KeyedHashAlgorithm algorithm = new HMACSHA256();
Encoding encoding = new UTF8Encoding();
algorithm.Key = encoding.GetBytes(secretKey);
result = Convert.ToBase64String(algorithm.ComputeHash(encoding.GetBytes(data.ToCharArray())));
return result;
}
Problem start here (I think). Scratchpad provides "data" to post, but I cant understand, how to use it (copy-paste from scratchpad):
POST /OffAmazonPayments_Sandbox/2013-01-01?AWSAccessKeyId=
&Action=GetOrderReferenceDetails
&SellerId=
&SignatureVersion=2
&Timestamp=2014-11-04T12%3A37%3A58Z
&Version=2013-01-01
&Signature=rEqRKP27Pklu%2BAmRLR%2ByRpUtfhNsVOWuGTQ7s%2FgkB2w%3D
&SignatureMethod=HmacSHA256
&AmazonOrderReferenceId= HTTP/1.1
Host: mws.amazonservices.com
x-amazon-user-agent: AmazonJavascriptScratchpad/1.0 (Language=Javascript)
Content-Type: text/xml
What is this? I am familiar of making request like this:
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "text/xml";
request.Host = "whatever host I need to use";
request.ContentLength = Encoding.UTF8.GetByteCount(dataAsString);
byte[] byteArray = Encoding.UTF8.GetBytes(dataAsString);
using (Stream dataStream = request.GetRequestStream())
{
dataStream.Write(byteArray, 0, byteArray.Length);
}
try
{
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
string responseAsString = streamReader.ReadToEnd();
}
}
catch (WebException exception)
{
HttpWebResponse exceptionalResponse = exception.Response as HttpWebResponse;
using (var streamReader = new StreamReader(exceptionalResponse.GetResponseStream()))
{
String responseAsString = streamReader.ReadToEnd();
}
}
Questions are:
Am I calculating signature properly?
How to construct web request?
Thanks for reading and trying to help!
EDIT:
Well, I finally got a response from MWS Amazon, that is not an error!
Steps I did to make it work:
Construct string that will be signed by hand - order of query parameters is important.
Construct url where I will post data by hand - again, order is important, but different from string signed before. Keys in signed string should be sorted using lexicographic byte ordering. Well, I dont know what kind of animal is that, so thats why I did everything by hand, by example taking scratchpad.
I struggled with this for a few days and it came down to the order of the parameters. I tried to find a solution to order the parameters without doing it by hand and finally found the answer. I created a SortedDictionary() at first still did not work. Then I saw an example from Claytondus nuget package that works with MWS and he had SortedDictionary(StringComparer.Ordinal). Once I did that it sorted correctly and got a good response.
I am trying write simple request to REST service.Follow to documentation from REST Service provider:
I should use in header Content-Type: application/json.
Response return in json format
For authorization proccess I have to send two headers one with APIKey and second with APISign
Controller PING in REST service to test code.
I use .net 2.0
string sha1String = APIKey + "/rest/ping" + APISecret;
string XRestApiSign = SHA1HashStringForUTF8String(sha1String);
string data = "";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(restServer);
request.Method = "POST";
request.ContentType = "application/json";
request.Headers.Add("X-Rest-ApiSign", XRestApiSign);
request.Headers.Add("X-Rest-ApiKey", APIKey);
request.ContentLength = data.Length;
StreamWriter requestWriter;
Stream webStream = request.GetRequestStream();
using (requestWriter = new StreamWriter(webStream, System.Text.Encoding.ASCII)) ;
{
requestWriter.Write(data);
}
request.BeginGetResponse((x) =>
{
using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(x))
{
List<string> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(response.GetResponseStream().ToString());
}
}, null);
I should get response string PONG but I get below message
Unexpected character encountered while parsing value: S. Path '', line 0, position 0
Is code OK ? Why I get this message?
This is mostly the case because the script that generates the JSON on the server side adds the byte order mark to the response.
In your case, however, you're trying to convert the stream to JSON, not the content of the stream. You need to read all text from the stream and deserialize the object from that. You need to call one of the methods on the stream that reads the content.
I modified my code with yours suggestion and it works. Now I have problem with send data :)
Subscription user1 = new Subscription
{
Email = "kubaIt#test.com.pl",
List = "xfct2bjcdv",
};
List<Subscription> user = new List<Subscription>();
user.Add(user1);
string json = JsonConvert.SerializeObject(user);
string data = json;
I added above. Other code is the same. I got error :The request was aborted: The request was canceled."
json = [{\"email\":\"kubaIt#test.com.pl\",\"list\":\"xfct2bjcdv\"}] //value from debuger
For the most part, I have managed quite quickly to move my code from standard .NET code to using RestSharp. This has been simple enough for GET processes, but I'm stumped for POST processes
Consider the following
var request = System.Net.WebRequest.Create("https://mytestserver.com/api/usr") as System.Net.HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/json;version=1";
request.Headers.Add("Content-Type", "application/json;version=1");
request.Headers.Add("Accepts", "application/json;version=1");
request.Headers.Add("Authorize", "key {key}");
using (var writer = new System.IO.StreamWriter(request.GetRequestStream())) {
byte[] byteArray = System.Text.Encoding.UTF8.GetBytes("{\n \"firstName\": \"Dan\",\n \"lastName\": \"Eccles\",\n \"preferredNumber\": 1,\n \"email\" : \"testuser#example.com\",\n \"password\": \"you cant get the wood\"\n}");
request.ContentLength = byteArray.Length;
writer.Write(byteArray);
writer.Close();
}
string responseContent;
using (var response = request.GetResponse() as System.Net.HttpWebResponse) {
using (var reader = new System.IO.StreamReader(response.GetResponseStream())) {
responseContent = reader.ReadToEnd();
}
This is fairly straight forward to move across, except for the serialisation code. Is there a particular way this has to be done for RestSharp? I've tried creating an object and using
var json = JsonConvert.SerializeObject(user);
restRequest.RequestFormat = DataFormat.Json;
restRequest.AddBody(json);
but the server still comes back with an error.
I'm also currently using JSON.NET for deserialization to an error object when the user passes in bad data. Is there a way I can deserialize to error object based on a single string using RestSharp?
You're close, but you don't need to worry about serialization with RestSharp.
var request = new RestRequest(...);
request.RequestFormat = DataFormat.Json;
request.AddBody(user); // user is of type User (NOT string)
By telling it that the format is JSON, then passing your already-serialized-as-JSON string, RestSharp is actually encoding it again as a string.
So you pass the string: {"firstName":"foo"} and it actually gets sent to the server as a JSON string object: "{\"firstName\":\"foo\"}" (note how your JSON is escaped as a string literal), which is why it's failing.
Note you can also use an anonymous object for the request:
var request = new RestRequest(...);
request.RequestFormat = DataFormat.Json;
request.AddBody(new{
firstName = "Dan",
lastName = "Eccles",
preferredNumber = 1,
// etc..
});
You use the same typed objects with the response (eg, RestSharp deserializes for you):
var response = client.Execute<UserResponse>(request);
// if successful, response.Data is of type UserResponse
This may be a pathetically simple problem, but I cannot seem to format the post webrequest/response to get data from the Wikipedia API. I have posted my code below if anyone can help me see my problem.
string pgTitle = txtPageTitle.Text;
Uri address = new Uri("http://en.wikipedia.org/w/api.php");
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
string action = "query";
string query = pgTitle;
StringBuilder data = new StringBuilder();
data.Append("action=" + HttpUtility.UrlEncode(action));
data.Append("&query=" + HttpUtility.UrlEncode(query));
byte[] byteData = UTF8Encoding.UTF8.GetBytes(data.ToString());
request.ContentLength = byteData.Length;
using (Stream postStream = request.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
}
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream.
StreamReader reader = new StreamReader(response.GetResponseStream());
divWikiData.InnerText = reader.ReadToEnd();
}
You might want to try a GET request first because it's a little simpler (you will only need to POST for wikipedia login). For example, try to simulate this request:
http://en.wikipedia.org/w/api.php?action=query&prop=images&titles=Main%20Page
Here's the code:
HttpWebRequest myRequest =
(HttpWebRequest)WebRequest.Create("http://en.wikipedia.org/w/api.php?action=query&prop=images&titles=Main%20Page");
using (HttpWebResponse response = (HttpWebResponse)myRequest.GetResponse())
{
string ResponseText;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
ResponseText = reader.ReadToEnd();
}
}
Edit: The other problem he was experiencing on the POST request was, The exception is : The remote server returned an error: (417) Expectation failed. It can be solved by setting:
System.Net.ServicePointManager.Expect100Continue = false;
(This is from: HTTP POST Returns Error: 417 "Expectation Failed.")
I'm currently in the final stages of implementing an C# MediaWiki API which allows the easy scripting of most MediaWiki viewing and editing actions.
The main API is here: http://o2platform.googlecode.com/svn/trunk/O2%20-%20All%20Active%20Projects/O2_XRules_Database/_Rules/APIs/OwaspAPI.cs and here is an example of the API in use:
var wiki = new O2MediaWikiAPI("http://www.o2platform.com/api.php");
wiki.login(userName, password);
var page = "Test"; // "Main_Page";
wiki.editPage(page,"Test content2");
var rawWikiText = wiki.raw(page);
var htmlText = wiki.html(page);
return rawWikiText.line().line() + htmlText;
You seem to be pushing the input data on HTTP POST, but it seems you should use HTTP GET.
From the MediaWiki API docs:
The API takes its input through
parameters in the query string. Every
module (and every action=query
submodule) has its own set of
parameters, which is listed in the
documentation and in action=help, and
can be retrieved through
action=paraminfo.
http://www.mediawiki.org/wiki/API:Data_formats