HTTPie is an HTTP client and an alternative to the famous cURL. Its goal is to make it easy to interact with HTTP servers, using a simple and natural syntax. This post will show how to quickly start using those benefits to test APIs.
There is actually another good tool I could recommended, Postman, which provides a user interface. But if you like the idea of being productive using a CLI tool, cURL and httpie are your options.
So you need to install HTTPie first
Assuming you already have Python 3 installed on your machine, you can install HTTPie as an add-on module for Python. Even better, as a good practice of seperating things, in a virtual environment. That's how I work, but it is just one of the options.
$ pip install httpie
As an alternative, you could use the package manager for your system, such as "apt-get", "yum", "homebrew", or other. For example, on macOS:
$ brew update
$ brew install httpie
Once done, you can call the HTTPie program by its name, adding the path if needed. You may want to it call it with the -h
option the first time to get see its usage instructions:
$ http -h
usage: http [--json] [--form] [--pretty {all,colors,format,none}]
[--style STYLE] [--print WHAT] [--headers] [--body] [--verbose]
[--all] [--history-print WHAT] [--stream] [--output FILE]
[--download] [--continue]
[--session SESSION_NAME_OR_PATH | --session-read-only SESSION_NAME_OR_PATH]
[--auth USER[:PASS]] [--auth-type {basic,digest}]
[--proxy PROTOCOL:PROXY_URL] [--follow]
[--max-redirects MAX_REDIRECTS] [--timeout SECONDS]
[--check-status] [--verify VERIFY]
[--ssl {ssl2.3,ssl3,tls1,tls1.1,tls1.2}] [--cert CERT]
[--cert-key CERT_KEY] [--ignore-stdin] [--help] [--version]
[--traceback] [--default-scheme DEFAULT_SCHEME] [--debug]
[METHOD] URL [REQUEST_ITEM [REQUEST_ITEM ...]]
Getting started with a demo or test service
We can use the http://httpbin.org service maintained by Kenneth Reitz, to start testing, if we do not have our own testing API server.
This service provides the /get endpoint to help test a GET request, which is what you do when you want to get an HTML page or read some information that is exposed by an API endpoint for that purpose.
$ http http://httpbin.org/get
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 257
Content-Type: application/json
Date: Sat, 14 Oct 2017 07:24:21 GMT
Server: meinheld/0.6.1
Via: 1.1 vegur
X-Powered-By: Flask
X-Processed-Time: 0.00122308731079
{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "HTTPie/0.9.9"
},
"origin": "85.170.243.247",
"url": "http://httpbin.org/get"
}
As another GET request example, we can test the /image/png endpoint which returns a PNG image.
$ http http://httpbin.org/image/png
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 8090
Content-Type: image/png
Date: Sat, 14 Oct 2017 06:53:08 GMT
Server: meinheld/0.6.1
Via: 1.1 vegur
X-Powered-By: Flask
X-Processed-Time: 0.000449180603027
+-----------------------------------------+
| NOTE: binary data not shown in terminal |
+-----------------------------------------+
Let's now submit a form with data using the /post endpoint.
$ http -f POST http://httpbin.org/post firstname=Kamon lastname=Ayeva
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 477
Content-Type: application/json
Date: Sat, 14 Oct 2017 07:02:47 GMT
Server: meinheld/0.6.1
Via: 1.1 vegur
X-Powered-By: Flask
X-Processed-Time: 0.000810146331787
{
"args": {},
"data": "",
"files": {},
"form": {
"firstname": "Kamon",
"lastname": "Ayeva"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
"Content-Length": "30",
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
"Host": "httpbin.org",
"User-Agent": "HTTPie/0.9.9"
},
"json": null,
"origin": "85.170.243.247",
"url": "http://httpbin.org/post"
}
I have also played with other demo or toy API servers, such as http://jsonplaceholder.typicode.com with it's /posts endpoint.
We can get the list of posts on the server:
$ http http://jsonplaceholder.typicode.com/posts
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
CF-Cache-Status: HIT
CF-RAY: 3ad8dd1586b614e5-CDG
Cache-Control: public, max-age=14400
Connection: keep-alive
Content-Encoding: gzip
Content-Type: application/json; charset=utf-8
Date: Sat, 14 Oct 2017 07:35:44 GMT
Etag: W/"6b80-Ybsq/K6GwwqrYkAsFxqDXGC7DoM"
Expires: Sat, 14 Oct 2017 11:35:44 GMT
Pragma: no-cache
Server: cloudflare-nginx
Set-Cookie: __cfduid=ddf4dd8ed5ea69bb8403aeba069f169331507966544; expires=Sun, 14-Oct-18 07:35:44 GMT; path=/; domain=.typicode.com; HttpOnly
Transfer-Encoding: chunked
Vary: Accept-Encoding
Via: 1.1 vegur
X-Content-Type-Options: nosniff
X-Powered-By: Express
[
{
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto",
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"userId": 1
},
{
"body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla",
"id": 2,
"title": "qui est esse",
"userId": 1
},
...
...
...
{
"body": "cupiditate quo est a modi nesciunt soluta\nipsa voluptas error itaque dicta in\nautem qui minus magnam et distinctio eum\naccusamus ratione error aut",
"id": 100,
"title": "at nam consequatur ea labore ea harum",
"userId": 10
}
]
We can add a post to the list of posts:
$ http -f POST http://jsonplaceholder.typicode.com/posts userId=1 title="Been trying this API" body="I been doing tests on this API using httpie and it works like a charm."
HTTP/1.1 201 Created
Access-Control-Allow-Credentials: true
CF-RAY: 3ad8ea5497b66956-CDG
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 149
Content-Type: application/json; charset=utf-8
Date: Sat, 14 Oct 2017 07:44:47 GMT
Etag: W/"95-MKeni/3m7kBc6y7Ue6geX3blGN0"
Expires: -1
Pragma: no-cache
Server: cloudflare-nginx
Set-Cookie: __cfduid=db6b89d4ce1115eb775764c905d003e1b1507967086; expires=Sun, 14-Oct-18 07:44:46 GMT; path=/; domain=.typicode.com; HttpOnly
Vary: Origin, X-HTTP-Method-Override, Accept-Encoding
Via: 1.1 vegur
X-Content-Type-Options: nosniff
X-Powered-By: Express
{
"body": "I been doing tests on this API using httpie and it works like a charm.",
"id": 101,
"title": "Been trying this API",
"userId": 1
}
What next?
Next, we can exercise on the real stuff out there, and look at cases like using API endpoints which require authentication. I am currently playing with the APIs of different services including DNSimple, GitHub and Digital Ocean. So expect one of them featured in a future post.