Using curl to POST request into ASP.NET Web Api service

by toni 14. March 2012 20:56

As you already know WCF Web Api is now ASP.NET Web Api. The WCF Web Api has an excellent built in test client which you can use to test your application manually. Just select method, which type of request to send, body format etc. and click Send.

wcf_webapi_testclient

Unfortunately the beta version of ASP.NET Web Api does not have the test client but according to asp.net forums they plan to include it in the final version. But there is even easier and faster way to send requests to your application – curl.

What is curl

curl is a command line tool for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet and TFTP. curl supports SSL certificates, HTTP POST, HTTP PUT, FTP uploading, HTTP form based upload, proxies, cookies, user+password authentication (Basic, Digest, NTLM, Negotiate, kerberos...), file transfer resume, proxy tunneling and a busload of other useful tricks.

Downloading curl

Go to curl website to download the tool. For this blog post I’m using the version Win32 Generic build version 7.2.4.0 (SSL SSH) binary release (single zip file).

Posting request

For the rest of this post I’m assuming you have unpacked the curl’s zip file into a folder and in this folder you also have file called request.txt which contains the raw json you want to POST. And of course you have your service up and running and waiting for a POST request.

Use the following command line to post the request (using the –v makes the output verbose so you can see what is going on).

curl -v -X POST -d @request.txt http://testserver/api/execute

Running the command produces following type of output

e:\>curl -v -X POST -d @request.txt http://testserver/api/execute
* About to connect() to testserver port 80 (#0)
*   Trying 127.0.0.1...
* connected
* Connected to testserver (127.0.0.1) port 80 (#0)
> POST /api/execute HTTP/1.1
> User-Agent: curl/7.24.0 (i386-pc-win32) libcurl/7.24.0 OpenSSL/0.9.8t zlib/1.2.5 libssh2/1.3.0
> Host: testserver
> Accept: */*
> Content-Length: 343
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 343 out of 343 bytes
< HTTP/1.1 400 Bad Request
< Cache-Control: private
< Content-Length: 350
< Content-Type: application/xml; charset=utf-8
< Server: Microsoft-IIS/7.0
< X-AspNet-Version: 4.0.30319
< X-Powered-By: ASP.NET
< Date: Wed, 14 Mar 2012 17:36:31 GMT
<
<?xml version="1.0" encoding="utf-8"?><ServiceErrorResponse xmlns:xsd=http://www.w3.org/2001/XMLSchema xmlns:xsi="http://www.w3.org/ 2001/XMLSchema-instance"><Reason>Validation failed</Reason> <Details>Validation failed: &#xD;
-- 'Name' should not be empty.</Details></ServiceErrorResponse>
* Connection #0 to host testserver left intact
* Closing connection #0

Now my service accepts both xml and json but for some reason the request fails (I’m using the Fluent Validation to validate the request). If you look at the Content-Type curl is sending you can see the reason for the error:

> Content-Type: application/x-www-form-urlencoded

That is most likely wrong unless your service is actually expecting data in that format. We can specify custom headers using the –H switch like this.

curl -v -H "Content-Type: application/json" -X POST -d @request.txt http://testserver/api/execute

While you specify the correct content type you should also specify the formats you accept in the response. As you can see you can use the –H option multiple times

curl -v -H "Content-Type: application/json" -H "Accept:application/json" -X POST -d @request.txt http://testserver/api/execute

This time you are greeted with HTTP status code 200 and you can see the response the service returned (I removed the non relevant parts of the command output).

e:\>curl -v -H "Content-Type: application/json" -H "Accept:applicat
ion/json" -X POST -d @request.txt http://testserver/api/execute
> POST /api/execute HTTP/1.1
> Content-Type: application/json
> Accept:application/json
>
* upload completely sent off: 343 out of 343 bytes
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
<
{"RequestId" : "client","Values" : [ {"Description" : "Result of the operation","Key" : "ResultCode","Value" : "1"}, {"Description" : "Current limit","Key" : "Limit","Value" : "300"}]}

Prettifying the response

As you can see the response is in json format but it is in single line. If you have large response it is pretty hard to decipher it. This can be fixed using something like Tidy JSON which makes the response look like this.

tidyjson_default

You can use the –palette command line to change the colors.

tidyjson_palette

Using batch file to simplify testing

Now all we have to do is simplify the process a bit. I decided to create simple batch file called post.bat with the following content (everything in the line beginning with curl should be in single line)

@ECHO OFF
set filename=%1
set uri=%2
curl -v -H "Content-Type: application/json" 
-H "Accept:application/json" -X POST 
-d @%filename% %uri% | tidyjson

Now I can post request into any uri by giving the file that contains the request and uri where it should be posted. The response will be piped to tidyjson which will make the response pretty to look at.

post.bat request.txt http://localhost/api/execute

That’s it. Hope this speeds up the testing and development.

Comments (2) -

Tatu T.
Tatu T. Finland
3/19/2012 9:28:02 PM #

Great post! For me it looks like an integration test. Do you run this manually time to time or have you integrated this to automated builds (TFS, TeamCity etc.)?

Toni
Toni Finland
3/20/2012 5:25:30 PM #

Yes this could be for integration testing. Test engineer could use curl to post requests but then again he could just use SoapUI to create actual test cases and store them in the source control. Faster to test. I plan to use this when developing because it is pretty easy to send the request and see the response. I don't need all the power that comes with SoapUI.

For automated integration tests we are probably just going to use ASP.NET Wep APIs HttpClient. This way we can write standard tests (mstest, nunit) and it is easier to write asserts on the actual response. The build server already deploys the packages into azure automatically but not for all roles (currently working on that one) and runs tests against the deployed roles.

Pingbacks and trackbacks (1)+

Comments are closed