Invoke-WebRequest should allow body content on DELETE, and perhaps any verb.
Whenever I run into an API that accepts data on DELETE, I am hamstrung by the client-side enforcement of which verbs can send a body and which cannot. For example, posting data on DELETE is used by many applications such as tumblr/collins to log reasons server-side. This may or may not be a good use of verbs and APIs, but I can't fix the server. I'm required to reimplement Invoke-WebRequest around System.Net.HttpWebRequest::CreateHttp to get the request in the shape that I need. Allowing the user to send a body with any verb is going to allow some needed flexibility in our world of varying APIs. Having a request fail because Invoke-WebRequest can only query perfect APIs will keep people from using it. Curl is a good example of how an API consumer should be less opinionated because it's a part of an imperfect world. With curl, if I construct an HTTP request that follows the core of HTTP but mismatches verbs, content, headers, etc, that's really my prerogative. If the goal for PowerShell 6.0 is to be amazing in the cloud, it has to be amazing in some rainier clouds.
As far as HTTP standards, body content on DELETE has some discussion here:
http://stackoverflow.com/questions/299628/is-an-entity-body-allowed-for-an-http-delete-request
Thank you for your time. I love love PowerShell.
> $PSVersionTable
Name Value
---- -----
PSVersion 6.0.0-beta
PSEdition Core
BuildVersion 3.0.0.0
CLRVersion
GitCommitId v6.0.0-beta.1
OS Darwin 16.5.0 Darwin Kernel Version 16.5.0: Fri Mar 3 16:52:33 PST 2017; root:xnu-3789.51.2~3/RELEASE_X86_64
Platform Unix
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
@JasonRitchie Thanks for your report!
@JasonRitchie is there a specific scenario/api that fails because we don't allow body on DELETE? I'm trying to prioritize this work. Thanks.
@SteveL-MSFT This appears to be fixed (likely due to upstream changes). I can no longer repro this.
@JasonRitchie Can you confirm this is no longer an issue?
$Body = "Test"
Invoke-WebRequest -Method DELETE -Body $Body -uri https://httpbin.org/delete
Invoke-RestMethod -Method DELETE -Body $Body -uri https://httpbin.org/delete
Result:
StatusCode : 200
StatusDescription : OK
Content : {
"args": {},
"data": "Test",
"files": {},
"form": {},
"headers": {
"Connection": "close",
"Content-Length": "4",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0 (Wi...
RawContent : HTTP/1.1 200 OK
Connection: keep-alive
Date: Tue, 03 Oct 2017 09:23:03 GMT
Via: 1.1 vegur
Server: meinheld/0.6.1
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
X-Powered-...
Forms :
Headers : {[Connection, System.String[]], [Date, System.String[]], [Via, System.String[]], [Server,
System.String[]]...}
Images : {}
InputFields : {}
Links : {}
ParsedHtml :
RawContentLength : 360
RelationLink : {}
args :
data : Test
files :
form :
headers : @{Connection=close; Content-Length=4; Host=httpbin.org; User-Agent=Mozilla/5.0 (Windows NT; Microsoft
Windows 10.0.15063 ; en-US) PowerShell/6.0.0}
json :
origin : 173.239.232.67
url : https://httpbin.org/delete
$PSversionTable:
Name Value
---- -----
PSVersion 6.0.0-beta.7
PSEdition Core
GitCommitId v6.0.0-beta.7-83-g417e9889399e2e0e6a90d52ff58ae08ec08b1cf2
OS Microsoft Windows 10.0.15063
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
I believe this was a lack of understanding on my part.
I dug back into this and tried to reproduce it, and I was able to, but resolving it was as simple as setting -ContentType correctly. This worked even when I rolled back to beta.1.
I'll give the details here for anyone else who may come across this.
In my initial naive attempt, you can see the body content is sent in query string format as the "data" content. The application I was hitting, tumblr collins, would have none of this. I have to admit I spent far too long stuck on this and I didn't have the understanding back then to identify the real issue.
Invoke-WebRequest -Method DELETE -Body $Body -uri https://httpbin.org/delete -Headers @{'authorization'='basic thing'}
StatusCode : 200 StatusDescription : OK
Content : {
"args": {},
"data": "baz=qux&reason=no+reason&foo=bar",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Authorization": "basic thing",
"Connection": "close",
...
RawContent : HTTP/1.1 200 OK
Connection: keep-alive
Server: meinheld/0.6.1
Date: Tue, 03 Oct 2017 14:01:03 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
X-Powered-By: Flask
X-Processed-...
Forms :
Headers : {[Connection, System.String[]], [Server, System.String[]], [Date, System.String[]], [Access-Control-Allow-Origin, System.String[]]...}
Images : {}
InputFields : {}
Links : {}
ParsedHtml :
RawContentLength : 535
Today as I revisited this I compared the behavior of POST to DELETE. DELETE doesn't set a content type by default. I have no problem with this behavior. In fact, I found this behavior defined in the official documentation.
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-6
If this parameter is omitted and the request method is POST, Invoke-WebRequest sets the content type to application/x-www-form-urlencoded. Otherwise, the content type is not specified in the call.
Here is all it took:
Invoke-WebRequest -Method DELETE -Body $Body -uri https://httpbin.org/delete -Headers @{'authorization'='basic thing'} -ContentType 'application/x-www-form-urlencoded'
StatusCode : 200 StatusDescription : OK
Content : {
"args": {},
"data": "",
"files": {},
"form": {
"baz": "qux",
"foo": "bar",
"reason": "no reason"
},
"headers": {
"Accept": "*/*",
"Authorization": "basic thing...
RawContent : HTTP/1.1 200 OK
Connection: keep-alive
Server: meinheld/0.6.1
Date: Tue, 03 Oct 2017 14:13:48 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
X-Powered-By: Flask
X-Processed-...
Forms :
Headers : {[Connection, System.String[]], [Server, System.String[]], [Date, System.String[]], [Access-Control-Allow-Origin, System.String[]]...}
Images : {}
InputFields : {}
Links : {}
ParsedHtml :
RawContentLength : 628
RelationLink : {}
I'll try to learn from this. I appreciate your time. I personally have no reason for this request to remain open.
Most helpful comment
I believe this was a lack of understanding on my part.
I dug back into this and tried to reproduce it, and I was able to, but resolving it was as simple as setting -ContentType correctly. This worked even when I rolled back to beta.1.
I'll give the details here for anyone else who may come across this.
In my initial naive attempt, you can see the body content is sent in query string format as the "data" content. The application I was hitting, tumblr collins, would have none of this. I have to admit I spent far too long stuck on this and I didn't have the understanding back then to identify the real issue.
Today as I revisited this I compared the behavior of POST to DELETE. DELETE doesn't set a content type by default. I have no problem with this behavior. In fact, I found this behavior defined in the official documentation.
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-6
If this parameter is omitted and the request method is POST, Invoke-WebRequest sets the content type to application/x-www-form-urlencoded. Otherwise, the content type is not specified in the call.Here is all it took:
I'll try to learn from this. I appreciate your time. I personally have no reason for this request to remain open.