Inspired by Julia Evans' curl exercises. Julia is awesome.
Learning a concept by using two different tools is often a great learning strategy for me. So here we go, let’s learn some HTTP.
I will use Emacs, which is better than using a terminal. Some benefits
include syntax highlighting of JSON and HTML in the responses, and the
fact that you can write an article without copying and pasting from
the terminal. And if you wanted to write an article like me, you would
like to create source code blocks, which you now get for free. I am
also having the curl
manual open inside woman
, which I have opened
through helm-man-woman
.
This may also serve as a meditation on user interface design. In curl
,
you always have to do something extra to make things work
pleasantly. That something extra is often some manual labour, like
splitting the command line options over multiple lines with backslashes.
Let’s use restclient.el
with ob-restclient
:
GET http://example.com
Now curl
:
curl "http://example.com"
Ok, let’s try httpbin.org
- a nice place to try out HTTP requests.
1
restclient.el
:
GET https://httpbin.org
curl
:
curl "https://httpbin.org"
2
Request https://httpbin.org/anything. httpbin.org/anything will look at the request you made, parse it, and echo back to you what you requested. curl’s default is to make a GET request.
The results here leak your IP.
restclient.el
:
GET https://httpbin.org/anything
curl
:
curl "https://httpbin.org/anything"
3
restclient.el
:
POST https://httpbin.org/anything
curl
:
curl -X POST "https://httpbin.org/anything"
4
Make a GET request to https://httpbin.org/anything, but this time add some query parameters
(set value=panda)
.
OK:
GET https://httpbin.org/anything?value=panda
curl
:
curl "https://httpbin.org/anything?value=panda"
5
Google’s robot.txt
is big. Oh well.
GET https://www.google.com/robots.txt
curl "https://www.google.com/robots.txt"
6
Make a GET request to https://httpbin.org/anything and set the header User-Agent: elephant
restclient.el
:
GET https://httpbin.org/anything
User-Agent: elephant
curl
:
curl -H "User-Agent: elephant" https://httpbin.org/anything
7
Make a DELETE request to https://httpbin.org/anything
restclient.el
:
DELETE https://httpbin.org/anything
curl
:
curl -X DELETE "https://httpbin.org/anything"
8
Request https://httpbin.org/anything and also get the response headers
restclient.el
already included them in all the other exercises.
curl
:
curl -i "https://httpbin.org/anything"
9
Make a POST request to https://httpbin.com/anything with the JSON body
{"value": "panda"}
restclient
makes this super simple.
POST https://httpbin.org/anything
{"value": "panda"}
curl
:
curl -X POST --data '{"value": "panda"}' "https://httpbin.org/anything"
10
Make the same POST request as the previous exercise, but set the
Content-Type
header toapplication/json
(because POST requests need to have a content type that matches their body). Look at the json field in the response to see the difference from the previous one.
Here it is very important that there is not any newlines between POST
and Content-Type
. It’s supposed to look like a real HTTP request. Read
https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages if that is
unclear.
restclient.el
:
POST https://httpbin.org/anything
Content-Type: application/json
{"value": "panda"}
curl
:
curl -X POST -H "Content-Type: application/json" "https://httpbin.org/anything"
11
restclient.el
:
GET https://httpbin.org/anything
Accept-Encoding: gzip
curl
:
curl -H "Accept-Encoding: gzip" "https://httpbin.org/anything"
Oh, the server sent me zip back. But restclient.el
translated it for
me. I wonder how much HTTP traffic is using gzip. It also messes up
the character encoding guessing mechanism of Emacs, so I silence the
results.
12
Put a bunch of a JSON in a file and then make a POST request to https://httpbin.org/anything with the JSON in that file as the body
JSON in ~/bunch.json
:
{
"fruit": "Apple",
"size": "Large",
"color": "Red"
}
restclient.el
:
POST https://httpbin.org/anything
< ~/bunch.json
curl
uses the -d option started with the letter @ to point to a file.
The -d @ command option accepts any resolvable file path, as long as
the path actually exists. Can’t use ~
though, so I am using the bash
variable $HOME
instead.
curl -X POST -d @$HOME/bunch.json "https://httpbin.org/anything"
13
Make a request to https://httpbin.org/image and set the header ‘Accept: image/png’. Save the output to a PNG file and open the file in an image viewer. Try the same thing with different Accept: headers.
curl -H "Accept: image/png" "https://httpbin.org/image" -o ~/httpbin_image.png
Got a beautiful image of a pig. -O
will write the name of the file the
same as the server.
restclient.el
is not made for file downlaods.
14
Make a PUT request to https://httpbin.org/anything
PUT https://httpbin.org/anything
curl -X PUT "https://httpbin.org/anything"
TODO 15
Request https://httpbin.org/image/jpeg, save it to a file, and open that file in your image editor.
TODO 16
Request https://www.twitter.com. You’ll get an empty response. Get curl to show you the response headers too, and try to figure out why the response was empty.
GET https://www.twitter.com
TODO 17
Make any request to https://httpbin.org/anything and just set some nonsense headers (like panda: elephant)
TODO 18
Request https://httpbin.org/status/404 and https://httpbin.org/status/200. Request them again and get curl to show the response headers.
TODO 19
Request https://httpbin.org/anything and set a username and password (with -u username:password)
TODO 20
Download the Twitter homepage (https://twitter.com) in Spanish by setting the Accept-Language: es-ES header.
TODO 21
Make a request to the Stripe API with curl. (see https://stripe.com/docs/development for how, they give you a test API key). Try making exactly the same request to https://httpbin.org/anything.
Downloading a SSL certificate
https://jvns.ca/blog/2017/01/31/whats-tls/
openssl s_client -connect mail.google.com:443
request.el stuff
(require 'request)
(request
"http://httpbin.org/get"
:params '(("key" . "value") ("key2" . "value2"))
:parser 'json-read
:success (cl-function
(lambda (&key data &allow-other-keys)
(message "I sent: %S" (assoc-default 'args data)))))