Skip to main content

Build a URL with query string parameters with curl

A combination of --get and --data/--data-urlencode allows you to write curl commands which are readable and expressive.

I want to write an HTTP GET in curl which:

How can I do that with curl?

Motivation

I’m writing some documentation for the Wikimedia Commons API, and I want to include some runnable examples. The various query parameters get baked into a single GET URL, but that makes it quite difficult to see what’s going on:

curl 'https://commons.wikimedia.org/w/api.php?action=query&list=logevents&letitle=File%3AMugeni%20Elijah%20-%20Behind%20tha%20sin%20ArtWork.png&format=xml&letype=delete'

There are five query parameters being passed to that URL! But this syntax makes it quite difficult to read and translate into another HTTP library.

In Python, I’m used to expressing the query parameters as a structured object (which also handles the URL encoding for you), for example:

import httpx

httpx.get(
    "https://commons.wikimedia.org/w/api.php",
    params={
        "action": "query",
        "list": "logevents",
        "letitle": "File:Mugeni Elijah - Behind tha sin ArtWork.png",
        "format": "xml",
        "letype": "delete"
    }
)

Compared to the curl command, this is easier for somebody to read and translate to another language, but it’s harder to copy/paste for a quick experiment.

Solution

I looked at the curl manpage, and I found the -G, --get flag (emphasis mine):

When used, this option makes all data specified with -d, --data, --data-binary or --data-urlencode to be used in an HTTP GET request instead of the POST request that otherwise would be used. curl appends the provided data to the URL as a query string.

This allows me to write the curl command in a more verbose, expressive way so somebody can see what’s going on:

curl --get 'https://commons.wikimedia.org/w/api.php' \
  --data 'action=query' \
  --data 'list=logevents' \
  --data-urlencode 'letitle=File:Mugeni Elijah - Behind tha sin ArtWork.png' \
  --data 'format=xml' \
  --data 'letype=delete'

(The --data-urlencode flag was a bonus discovery, which saves me from URL encoding parameters by hand.)