How do I fetch a URL in Racket?

The landscape for making HTTP requests in Racket is surprisingly fussy. There’s the net/http library, which is built-in to Racket. And there’s the http package. The former might be too simple for your needs, and the latter might seem too clumsy. What to do?

Why is it so hard to just fetch a URL?

To my knowledge, there’s currently no very simple, do-what-I-mean HTTP client for Racket. But here’s a simple code snippet that may help. After the code there’s a discussion of what this snippet is doing.

To use this function, load the code and then try:

1
(http-request "http://twofour54.com")

(or any other URL, for that matter). The function has a simple interface. Only one argument is mandatory, namely, a URL. Reasonable assumptions are made about the low-level HTTP details (e.g., we assume that the HTTP method you want to use is GET), but you can change them by using suitable keyword arguments.

Background

This code is based on Greg Hendershott’s http package. That package is, in my judgment, the best candidate for an HTTP client for Racket.

(The http package isn’t built-in to Racket, so make sure you do raco pkg install http.)

There are a number of functions in the http package, but the two in focus here are call/input-request and call/output-request. To decide which one you should use, ask yourself:

Do I need to send data along with my request?

If so (as is usually the case with HTTP POST and PUT), use the package’s call/output-request function. If not (e.g., you’re just using GET, DELETE, OPTIONS), use call/input-request.

(A more general purpose function, call/requests, is also available in the http package, but I find that function fussier to use. I prefer to use the two aforementioned functions instead.)

Here’s a simple invocation:

1
2
3
4
5
6
(call/input-request
  "1.1"
  "GET"
  "http://twofour54.com"
  empty
  read-entity/bytes)

Here’s a simple POST request:

1
2
3
4
5
6
7
8
(call/output-request
  "1.1"
  "POST"
  "http://twofour54.ae"
  #"abc"
  #f
  empty
  read-entity/bytes)

My code simply delegates to one of these two functions from the http package, depending on a reasonable guess about what data you’d like to send. Namely, if it looks like you’re not trying to send any data, then we use call/input-request. Otherwise, we use call/output-request.