github soundcloud
http
Sep 4, 2019
4 minutes read

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 to application/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)))))

Back to posts