7

I'm using an API that requires me to set the method to GET and include a message body. However when I try to do this I get the following error: "Cannot send a content-body with this verb-type". I read that the HttpWebRequest class does not support this and is the reason for the exception. Is there a work around?

This is my current code: data is a json string encoded as a byte array

HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "GET";
request.ContentType = "application/json";
request.ContentLength = data.Length;
using (Stream requestStream = request.GetRequestStream()) {
    requestStream.Write(data.ToArray(), 0, (int)data.Length);
}

This is the PHP code I'm trying to emulate

<?php
$data = array("id" => "1234");
$data_string = json_encode($data);
$ch = curl_init('url');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'Content-Length: ' . strlen($data_string))
);
$result = curl_exec($ch);
var_dump($result);
?>

Thank you,

Fernando
  • 550
  • 1
  • 6
  • 16
  • Possible duplicate of [Possible for HttpClient to send content or body for GET request?](https://stackoverflow.com/questions/43421126/possible-for-httpclient-to-send-content-or-body-for-get-request) – Ian Kemp May 09 '19 at 12:01

3 Answers3

2

What does one call an API that actively goes against REST? "HASTE"? "DISQUIET"?

With a bit of luck they service just doesn't care what the verb is and the PHP code was just happening to use GET and hit the bug that the server didn't block it which is a pretty minor bug as long as it behaves correctly, and it'll be fine with POST.

Failing that, your best bet is to see if they have an alternative method that either (if it's a reading request that naturally fits GET) accepts parameters in the URI with perhaps appropriate headers being used as per RFC 2616, or else can accept something through POST, GET etc.

If that doesn't work, you'll have to build an HTTP client on top of TcpClient. Which would be pretty horrible.

Jon Hanna
  • 102,999
  • 9
  • 134
  • 232
  • I'm starting to think I will have to go that route. But I will try to ask if they can accept the parameter in the URI. It seems very simple to me. – Fernando Aug 18 '12 at 02:37
  • 1
    Well, I will never complain about the violations of REST that I have to put up with again. No, that's a lie and I will always complain about them, but something insisting on a body with GET is the worse I've ever seen. (You have confirmed that it refuses to handle the same data with POST, yes?) – Jon Hanna Aug 18 '12 at 08:55
  • Yes, as POST is used to perform an update of the entities, and it only returns a status of the operation, and a message if the operation fails as a JSON object. I'll try to convince the API developers to modify their GET method, otherwise I will have to create a separate call using the TcpClient. Thank you. – Fernando Aug 18 '12 at 10:49
  • @JonHanna - I think posting a body in a GET method is goofy also; unfortunately, I think some of the advanced Elasticsearch 6.6 _search examples currently pass a body when using a GET method. I need to emulate these examples in ASP.NET. The HttpWebRequest isn't letting me do that and I don't have easy access to CURL: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html – Shawn Eary Jan 31 '19 at 01:27
  • I tested HttpWebRequest, WebRequest, and HttpClient. They all return an exception if you include a content body in a GET request. C# is not your friend for this problem. I do not know how your system is built. Is it possible to move your api request to a website and use javascript to make the request? Javascript will permit you to include a content body in a GET request. – Jason Williams Apr 09 '19 at 14:47
  • Snark from 2012 made sense, but it looks like time to prepare for GETs with bodies accepted as RESTful -- [good discussion w/ details of RFC changes here](https://stackoverflow.com/questions/978061/http-get-with-request-body#comment68112820_983458). Regardless, as ShawnEary remarks, there are valid _and non-trivial_ use cases for bodied GETs whether we believe it should or shouldn't be RESTful. I'd bet @IanKemp 's note that Core ([aka.NET 5](https://devblogs.microsoft.com/dotnet/introducing-net-5/)) now [supports bodied GETs](https://stackoverflow.com/a/47902135/1028230) isn't a MS mistake. 2¢ – ruffin May 22 '19 at 12:32
2

It is entirely possible, but you have to use the newer HttpClient class: https://stackoverflow.com/a/47902348/70345

Ian Kemp
  • 24,155
  • 16
  • 97
  • 121
  • 2
    -1 I tried this. base > System.Net.ProtocolViolationException > base > System.InvalidOperationException > "Cannot send data when method is: GET" – minnow Mar 12 '18 at 02:25
  • @minnow Thank you for alerting me to this - I posted the answer a while after I had actually tested this code, so I forgot that I was only able to get it to work with Core - I have amended it to note this. – Ian Kemp Mar 12 '18 at 08:18
  • The reason why this isn't supported is that you're not supposed to send body data with GET requests, the entire request should be the URL with headers to guide the server, the body should be ignored. Of course, a broken web service requires a broken client but in the general sense asking how to send body data with a GET request is the wrong question entirely. – Lasse V. Karlsen Mar 12 '18 at 08:26
  • 3
    @LasseVågsætherKarlsen There is nothing in the HTTP spec that explicitly prohibits sending a request with a body when using a body-less verb. And there certainly are scenarios where, IMO, doing so is valid: in particular, if your request is very large (too large to encode all the parameters in the URL) - Elasticsearch does this, for example. Now, you might say "in that case, use POST" but semantically (from a RESTful standpoint at least), POST is to update a resource while GET is to retrieve it. Anyhow - I don't want to get into a semantic/religious war in comments. – Ian Kemp Mar 12 '18 at 09:08
  • 2
    GET is documented in the [HTTP specification](https://tools.ietf.org/html/rfc2616#section-9.3) to retrieve information that "is identified by the Request-URI", which does not include body. I understand and know that a lot of services "abuse" (my opinion, no need to respond to that) the GET request and send a lot of data but it is in fact not in the specification. Obviously it can be done technically and I've seen quite a lot of services that use it, but it is not according to spec. But yes, no need to create a big thread about it, it's going to end as a matter of opinion anyway :) – Lasse V. Karlsen Mar 12 '18 at 10:21
  • 1
    It is a recommendation not to do it, it isn't part of the SPEC. that's why .net core implemented it, coz there is a need and semantically it doesn't make sense to send post requests to retrieve data. mono runtime doesn't though so clearly it is a matter of preference. – kkarakk May 09 '19 at 08:56
-3

It is not recommended to send content with a GET request. See this post for further details: HTTP GET with request body

And this is what Roy Fielding has to say about the topic.

Community
  • 1
  • 1
Dennis Traub
  • 46,924
  • 7
  • 81
  • 102
  • 4
    Thanks. I understand this, but it is out of my hands. This is a third party API which I need to use. – Fernando Aug 18 '12 at 02:36
  • 7
    Ehm, do you know this is how ElasticSearch's REST API works? Sending complex queries requires a request body and a GET request. Conceptually this is very much they way REST works. Any other verb would be wrong, and you can't always squeeze comples queries into the URL. I'm surprised the HttpWebRequest object can't handle that. – lasseschou Oct 23 '13 at 09:01