I'm building a RESTful API client using C# .NET 3.5.
I first started building it with the good old HttpWebClient (and HttpWebResponse), I could do whatever I wanted with. I were happy. The only thing I stumbled upon was the automatic deserialization from JSON response.
So, I've heard about a wonderful library called RestSharp (104.1) which eases the development of RESTful API clients, and automatically deserialize JSON and XML responses. I switched all my code on it, but now I realize I can't do things I could do with HttpWebClient and HttpWebResponse, like access and edit the raw request body.
Anyone has a solution?
Edit: I know how to set the request body (with request.AddBody()), my problem is that I want to get this request body string, edit it, and re-set it in the request (in other words: updating the request body on the fly)
The request body is a type of parameter. To add one, you can do one of these...
req.AddBody(body);
req.AddBody(body, xmlNamespace);
req.AddParameter("text/xml", body, ParameterType.RequestBody);
req.AddParameter("application/json", body, ParameterType.RequestBody);
To retrieve the body parameter you can look for items in the req.Parameters collection where the Type is equal to ParameterType.RequestBody.
See code for the RestRequest class here.
Here is what the RestSharp docs on ParameterType.RequestBody has to say:
If this parameter is set, it’s value will be sent as the body of the
request. The name of the Parameter is ignored, and so are additional
RequestBody Parameters – only 1 is accepted.
RequestBody only works on POST or PUT Requests, as only they actually
send a body.
If you have GetOrPost parameters as well, they will overwrite the
RequestBody – RestSharp will not combine them but it will instead
throw the RequestBody parameter away.
For reading/updating the body parameter on-the-fly, you can try:
var body = req.Parameters.FirstOrDefault(p => p.Type == ParameterType.RequestBody);
if (body != null)
{
Console.WriteLine("CurrentBody={0}", body.Value);
body.Value = "NewBodyValue";
}
Or failing that, create a new copy of the RestRequest object with a different body.
Related
I currently have an endpoint in my project:
[HttpPost("process")]
public IActionResult Process (string Val1, [FromBody] object Json)
{
//processing.....
Return Ok(...);
}
And on my client side I am trying to call this endpoint with WebClient like so:
string response = null;
string body = "{}";
using (var client = new WebClient())
{
client.UserDefaultCredentials = true;
client.Headers.Add(HttpRequestHeader.ContentType, "application/json; charset=utf-8");
response = client.UploadString("localhost:55555/api/process?Val1=Param", body);
}
Here's where my concerns are:
For this endpoint, I will typically be passing a JSON object
However, I want this endpoint to also NOT require a body, I would want it to be empty, as the endpoint should not require it
If you look at my body variable - I am setting it to "{}" otherwise I've not found a different way to pass "EMPTY" body to the endpoint
Questions:
How do I properly pass an EMPTY body to this endpoint? (this endpoint will be used by different clients, and I am just looking for best practice approach to this?
In my endpoint, I have [FromBody] object Json parameter. Is it a better practice to have it be as object or can I alternatively do JObject that could still accept an Empty body
Forgive my "noobness" with these questions if they seem obvious, I'm just getting started in the API development and want to make sure I am using best practices.
You're currently using a WebClient, which is outdated in favour of HttpClient (see this answer). When using HttpClient you can post empty bodies as follows: await client.PostAsync("localhost:55555/api/process?Val1=Param", null);
As for your second question. Look into Data Transfer Objects, aka DTOs. They are in a nutshell dumb types you can use purely for passing and receiving data through your API, you can add things like validation to them as well. Using object or JObject is only needed if you're receiving dynamic data, otherwise use DTOs where possible.
I want to call an endpoint with a Put command.
In Postman
I can put example https://example.com/customers/106. I then add a body of type application/json (under raw).
When I Put this body to the endpoint, I get a 200 OK.
The endpoint I use requires two custom headers and a content-type, which I have made under headers. So I add three headers: X-AppSecretToken, X-AgreementGrantToken and the Content-Type (to application/json).
In RestSharp
Here I use the following. The putstr is the exact same body I Put as I do in Postman:
var restclient = new RestSharp.RestClient("https://example.com");
var request = new RestRequest("/customers/" + customerId, Method.PUT);
request.AddHeader("X-AppSecretToken", systemToken);
request.AddHeader("X-AgreementGrantToken", userToken);
request.AddHeader("Accept", "application/json");
request.AddJsonBody(putstr);
var response = restclient.Execute(request);
Now, when I do this, I get the following response which is a custom error from the API I am calling:
"{\"message\":\"Error converting value SOME STUFF}}\\\" to type 'eco.rest.Models.Customer'. Path '', line 1, position 605.\",\"errorCode\":\"E00500\",\"developerHint\":\"The JSON payload could not be parsed. The error message should give you a good indication of where the error is located. One common reason for this error is a missing '{' or a '}' in your payload.\",\"logId\":\"123fc6fb4964a141f612ae8ae7571446\",\"httpStatusCode\":400,\"logTime\":\"2018-05-20T21:56:56\"}"
How to fix?
Normally, I'd never ask this question. If someone else asked, I would say: open Fiddler or a similar tool and see how requests are different.
I have some troubles with this, because it's HTTPS.
When I debug through my code, I simply don't see the call inside Fiddler. I also installed Charles, but also no luck. Not sure what the problem is.
However, I thought that someone who reads this can probably come up with the problem. My own assumptions are I maybe have added the headers in a wrong way, the JSON body is encoded different or similar - but I am really unsure how to move on. I hope someone can help!
Your putstr value seems to be a JSON value.
AddJsonBody will convert this JSON value into another JSON value.
You should use the original object instead of putstr.
I'm having issues figuring out how to create a put request using RestSharp.
I need to pass an integer followed by a JSON body in the same request.
So far I have this:
for (var i = 0; i < ReorderedTasks.Count; i++) {
var reorderedTasksJson = new JavaScriptSerializer().Serialize(ReorderedTasks[i]);
var request = new RestRequest("api/task/5/{ID}/", Method.PUT);
request.AddParameter("ID", ReorderedTasks[i].ID.ToString(), ParameterType.UrlSegment);
request.AddParameter("application/json; charset=utf-8", reorderedTasksJson, ParameterType.RequestBody);
client.Execute(request);
}
I've tested out the JSON ad requestBody on POST and it works fine. I think my issue is with the first parameter I'm trying to pass ReorderedTasks[i].ID , I'm not sure if I'm handling the passing of this correctly.
I've initialised client at the beginning of my class.
Problem is the DB isn't updating and I need to isolate the problem. Is the above the correct way in dealing with my two parameters needing passed?
I suggest to put ReorderedTasks[i].ID.ToString() directly to url path.
var request = new RestRequest($"api/task/5/{ReorderedTasks[i].ID.ToString()}/", Method.PUT);
It will help to reduce possible problems with http request format.
I'll add it here, so someone will benefit from it.
If your endpoint URL have parameters like ?param=value¶m2=value that you want to pass along with request RestSharp's AddParameter(string, string) won't work with PUT method (but it works just fine with GET or if endpoint doesn't have URL parameters, so it is deceiving)
Use AddParameter(string, string, ParameterType.QueryString) in order to PUT Method work correctly.
Well it depends on what does the webApi expect..
You could use Fiddler to inspect what being sent through the wire and what response You are getting (http://www.telerik.com/fiddler)
Also - here are some sample's how other users use RestSharp
How do I use PUT in RestSharp?
I am using RestSharp for developing on the client side. I am also using Ruby Grape gem for my custom API on server side. Grape gem can do versioning by setting Accept HTTP header f.e to application/vnd.twitter-v1+json
And test command via console works perfect
curl -H Accept=application/vnd.twitter-v1+json /statuses/public_timeline
But when I am trying to set up header for RestRequest I am getting error 404 on the server.
I have no idea why so. I have found another issue that server returns 406 error - but in my case 404.
How can I put custom value for Accept header?
You can set a custom Accept header with the AddHeader method...
var client = new RestClient("http://example.com/api");
var request = new RestRequest("statuses/public_timeline", Method.GET);
request.AddHeader("Accept", "application/vnd.twitter-v1+json");
var response = client.Execute(request);
var json = response.Content;
This should work fine if you are willing to deserialize the JSON yourself.
If you want to make use of the generic Execute<T> method, which does automatic deserialization for you, you will run into problems...
From the RestSharp documentation about deserialization:
RestSharp includes deserializers to process XML and JSON. Upon receiving a response, RestClient chooses the correct deserializer to use based on the Content Type returned by the server. The defaults can be overridden (see Customization). The built-in content types supported are:
application/json – JsonDeserializer
application/xml – XmlDeserializer
text/json – JsonDeserializer
text/xml – XmlDeserializer
* – XmlDeserializer (all other content types not specified)
This is saying that, by default, if the response's content type is not one of those listed, RestSharp will attempt to use the XmlDeserializer on your data. This is customizable though with extra work.
I am currently experimenting with the HTTP request. I have successfully managed to do get requests and I have read on doing post request with HTTP request.
Now I am trying to work with the yahoo API and in order to use the Yahoo api it states that at
The Message Management API can be used to send a message to another
Yahoo! Messenger contact. The API is very simple to use, as shown
here. Note that the contact that the message is sent to is part of the
URI, using the following format:<server>/v1/message/<network>/<contactID>
POST /v1/message/yahoo/targetYahooId?sid=msgrsessionid
Host: rcore1.messenger.yahooapis.com
Authorization: < Standard OAuth credentials >
Content-Type: application/json;charset=utf-8
Content-Length: 25
{
"message" : "Hey there"
}
Now I have an OAuth string which I obtained from get using the HttpWebRequest object.
The string is something like this
oauth_token=A%3Dvh....aRg--&oauth_token_secret=bd46a....c9239&oauth_expires_in=3600&oauth_session_handle=ALtT.....3J1N4Zg--&oauth_authorization_expires_in=784964948&xoauth_yahoo_guid=TUSKED5...NCIA
UPDATE
Now my question are as follows :
1- If I am using WebRequest object in C# what would my URI look like
2- I understand that it requires a JSON type object. How do i even know what OAuth parameters are ?
One thing you'll need to change is the content type:
request.ContentType = "application/json;charset=utf-8";
And of course, the url.
you need to change the url on the line with the url in it
you need to change the content-type line
you need to make the payload into a json string then convert it to a byte array (byteArray in the sample)
either assemble the json by hand "{ foo:'bar'}" etc or use json.net
and set the content-length
Looks like it's expecting a JSON object for the request body. Depending on the version of .NET you're using, you can either use a Javascript serializer as shown here (https://stackoverflow.com/a/7003815/939080) or JSON.NET (http://james.newtonking.com/projects/json-net.aspx) to convert your form collection into JSON output.
You are asking an open-ended question that would require people to write a bunch of code for you if you want a specific and complete answer. As others have pointed out, there are several issues that you'd need to deal with:
The JSON payload, which would be a straightforward matter of putting the JSON string in the request body via the byteArray used in the code sample.
The content type, which you would need to change as described by jrummell.
The OAuth credentials, which is a kettle of fish you'll need to read about, understand, and acquire a library for. Here's a good place to start looking for a library.