Ombyggnad 2026/2027 pågår - döda länkar förekommer. Mer information

Praktisk guide för att hålla dig till cURL

2026-04-17 på Anders Ytterströms webblogg

Från Just use cURL

Q: How do I organize my requests?
A: Put your shell scripts into directories, genius.

Så låt oss göra detta med praktiska exempel! Jag gjorde detta nyligen, så jag kan gå igenom det bit för bit hur jag gjorde.

Information om API jag önskar testa:

Följande setup kommer skapas i detta inlägg:

Så här ser en typisk session ut:

. .envs/prod/sandbox
./renew-token
./saker/GET/lista-alla-saker.curl
./saker/POST/skapa-sak.curl "saken"
./saker/DELETE/radera-sak.curl "saken"
./saker/POST/skapa-sak.curl "sak2"
./saker/PUT/uppdatera-sak.curl "sak2" "saken"
./saker/DELETE/radera-sak.curl "saken"

Skapa nytt git-repo

Det går såklart att göra detta med annan backup-lösning också, men git är vad jag föredrar.

git init just-use-curl
cd just-use-curl

Jag skapar direkt en ignore-lista.

cat <<END > .gitignore
.curl-*-headers-file
END

Grundläggande filstruktur

Skapa litet filer och mappar:

mkdir {.envs/{test,pt,prod},.tests}
touch .envs/{test,pt,prod}/{sandbox,production}
touch {renew-token,set-secrets,who-am-i}
chmod +x {renew-token,set-secrets,who-am-i}
cat <<END > .gitignore

Nedbrytning om vad filerna gör:

Nedbrytning av script

Det är primärt tre script, och ett valfritt script.

init-env

Scriptet sätter upp en miljö genom att fråga efter två saker:

Detta är innehållet:

#!/bin/sh
step=1
uenv=$(echo "$1" | tr "[:lower:]" "[:upper:]")
printf "Skapar miljö - %s\n" "$uenv"
printf "[%s/2] Ange API_ENDPOINT_URL och tryck ENTER: " "$step"
read -r aeu
step=$((step + 1))
printf "[%s/2] Ange TOKEN_ENDPOINT_URL och tryck ENTER: " "$step"
read -r teu
step=$((step + 1))
mkdir -p .envs/"$1"
touch .envs/"$1"/."$1"
cat <<END > .envs/"$1"/."$1"
export TOKEN_ENDPOINT_URL=$teu
export API_ENDPOINT_URL=$aeu
END

who-am-i

Ett script som skriver ut den aktuella kontexten. Kontexten väljs genom att source:a en av env-filerna, t ex såhär:

. .envs/pt/sandbox; ./who-am-i

Detta är innehållet.

#!/bin/sh
echo "TOKEN_ENDPOINT_URL:   $TOKEN_ENDPOINT_URL"
echo "API_ENDPOINT_URL:     $API_ENDPOINT_URL"
echo "API_KEY_TYPE:         $API_KEY_TYPE"
echo "CLIENT_KEY:           $CLIENT_KEY"

renew-token

Ett POSIX-script som kollar så att vi valt en kontext, och om vi har det - så skapas och sparas en ny access token.

Detta är innehållet:

#!/bin/sh
: "${CLIENT_KEY?CLIENT_KEY saknas - aktivera en miljö?}"
: "${CLIENT_SECRET?CLIENT_SECRET saknas - aktivera en miljö?}"
: "${API_KEY_TYPE?API_KEY_TYPE saknas - aktivera en miljö?}"
: "${TOKEN_ENDPOINT_URL?TOKEN_ENDPOINT_URL saknas - aktivera en miljö?}"
: "${API_ENDPOINT_URL?API_ENDPOINT_URL saknas - aktivera en miljö?}"
CREDENTIALS=$(echo "$CLIENT_KEY:$CLIENT_SECRET" | base64)
TOKEN=$(curl -s -X POST "$TOKEN_ENDPOINT_URL" -d "grant_type=client_credentials" -H "Authorization: Basic $CREDENTIALS" | jq '.["access_token"]' | sed -e "s/\"//g")
cat <<END > .curl-"$CLIENT_KEY"-headers-file
User-Agent: $USER-$(curl -V | head -n1 | awk '{print $1$2;}')
Accept: application/json
Authorization: Bearer $TOKEN
END

Valfritt: set-secrets

Ett script som ger instruktioner för att klistra in consumer keys och consumer secrets per miljö.

BRa att ha, men kan göras manuellt också. Här är innehållet:

#!/bin/sh
API=$(basename "$PWD")
clear
client_credentials () {
	step=1
	echo "[$step/5] Gå till API i utvecklarportalen, och dess Subscriptions."
	echo "      Välj där korrekt Application, och använd kopieringsverktyget"
	echo "      på värdena."
	echo "      OBS! ingen inklistring av *secrets* kommer att skrivas på"
	echo "      skärmen av säkerhetsskäl."
	for env in "sandbox" "production"; do
		uenv=$(echo "$env" | tr "[:lower:]" "[:upper:]")
		step=$((step + 1))
		printf "[%s/5] Klistra in %s \"Consumer Key\" och tryck ENTER: " "$step" "$uenv"
		read -r ck
		step=$((step + 1))
		printf "[%s/5] Klistra in \"Consumer Secret\" för %s och tryck ENTER: " "$step" "$uenv"
		stty -echo
		read -r cs
		stty echo
		echo ""
		cat <<- END > ./.envs/"$1"/"$env"
		. ./.envs/$1/.$1
		export API_KEY_TYPE=$env
		export CLIENT_KEY=$ck
		export CLIENT_SECRET=$cs
		END
	done
	printf "Consumer key+secret är sparad för %s!\n" "$1"
}
echo "Sätter consumer key+secret för: $API"
for env in "test" "pt" "prod"; do
	yN=""
	while true; do
	    printf "Sätt secrets för %s i %s? [y/N]: " "$API" "$env"
	    read -r input
	    case "$input" in
		[yY])
		    yN="y"
		    break
		    ;;
		""|[nN])
		    yN="n"
		    break
		    ;;
		*)
		    printf "[!] Felaktigt svar! Ange \"y\" eller \"n\".\n"
		    ;;
	    esac
	done
	if [ "$yN" = "y" ]; then
	    client_credentials "$env"
	fi
done

Skapa miljöerna

Varje miljö (test, pt och prod) har två endpoints, sandbox och production.

Följande kommandon skapar miljöerna:

./init-env test
./init-env pt
./init-env prod

Jag vill sedan ange OAuth-keys och -secrets, det gör jag med:

./set-secrets

Verifiera så allt funkar:

. .envs/pt/sandbox
./who-am-i
./renew-token

Skapa några endpoints

För att skapa endpoints används följande filstruktur:

Exempel på hur detta kan se ut:

thing/
├── GET
│   ├── list-all.curl
│   └── list-selection.curl
└── POST
    ├── append-new.error.curl
    └── append-new.ok.curl

Endpoint som bara hämtar data (GET, OPTIONS, HEAD)

Behöver inga argument.

Exempel på hur det kan se ut:

#!/bin/sh
res="thing"
curl -s \
-H @.curl-"$CLIENT_KEY"-headers-file \
"$API_ENDPOINT_URL"/"$res" \
| python3 -m json.tool

Standardverbet i cURL är GET. Använd -X [OPTIONS, HEAD] för att ändra verbet.

(I exemplet här är det ett JSON-API, så Pythons inbyggda json.tool används för att snygga till utskriften)

Endpoints som behöver indata (t ex POST, PUT, PATCH)

Behöver argument, t ex via stdin eller som variabel i filen.

Exempel på hur det kan se ut:

#!/bin/sh
res="thing"

# definiera data i filen
# exempel: ./thing/POST/new.curl 
data="code=success&payload=allgood"
resp=$(curl -s -w "%{http_code}\n" \
-H @.curl-"$CLIENT_KEY"-headers-file \
-d "$data" "$API_ENDPOINT_URL"/"$res")

# skicka in stdin som payload
# exempel: cat payload.txt | ./thing/POST/new.curl 
resp=$(curl -s -w "%{http_code}\n" \
-H @.curl-"$CLIENT_KEY"-headers-file \
-d "$(cat -)" "$API_ENDPOINT_URL"/"$res")

# skicka in första argumentet som data
# exempel: ./thing/POST/new.curl "foo=1" 
resp=$(curl -s -w "%{http_code}\n" \
-H @.curl-"$CLIENT_KEY"-headers-file \
-d "$1" "$API_ENDPOINT_URL"/"$res")

# skicka in en sträng som data och placera den i nyckeln "payload"
# exempel: ./thing/POST/new.curl hej 
resp=$(curl -s -w "%{http_code}\n" \
-H @.curl-"$CLIENT_KEY"-headers-file \
-d "payload=$1" "$API_ENDPOINT_URL"/"$res")

# Skriv ut HTTP-statuskod från svar om ingen övrig data skickades med,
# och formattera JSON om sådan finns
if [ "$(echo "$resp" | wc -w)" -eq 1 ]
then
	echo "HTTP $resp"
else
	echo "$resp" | tr -d '\n' | sed -r 's/[0-9]+$//' | python3 -m json.tool
fi

Standardverbet när data skickas (curl -d) är POST. Använd -X [DELETE, PATCH, PUT] för att ändra verbet.

(I exemplet här är det ett JSON-API, så Pythons inbyggda json.tool används för att snygga till utskriften)

Endpoints som behöver ange ett ID eller referens (GET, DELETE, PUT, PATCH)

#!/bin/sh
res="thing"

# Ange id/referens med första argumentet,
# exempel: ./thing/DELETE/delete-single.curl 23 
curl -X DELETE -s -w "HTTP %{http_code}\n" \
-H @.curl-"$CLIENT_KEY"-headers-file \
"$API_ENDPOINT_URL"/"$res"/"$1"

# Ange id/referens med stdin
# exempel: echo 23 | ./thing/DELETE/delete-single.curl 
curl -X DELETE -s -w "HTTP %{http_code}\n" \
-H @.curl-"$CLIENT_KEY"-headers-file \
"$API_ENDPOINT_URL"/"$res"/"$(cat -)"

Använd -X [DELETE, PATCH, PUT] för att ändra verbet, eller skippa -X för att falla tillbaka på GET. Kika på tidigare exempel på hur koden kan utökas med en if-sats som skriver ut statuskod eller paylaod beroende på svar.

(I exemplet här är det ett JSON-API, så Pythons inbyggda json.tool används för att snygga till utskriften)

Skala över tid

Först av allt - versionshantering med git är en bra start, och kan nog räcka med en bra tillämpning av taggar och branches.

Jag rekommenderar dock att låta filstrukturen spegla alla versioner av API som ligger i produktion, då det inte ovanligt att flera gamla och nya versioner samexisterar, te x på grund av krav på bakåtkompabilitet eller migreringsperiod.

Jag hade därför gjort något liknande över tid:

apis
├── README
├── demo-api
│   └── v2
│   │   ├── ...
│   │   ├── init-env
│   │   ├── README
│   │   ├── renew-token
│   │   ├── set-secrets
│   │   └── who-am-i
│   └── v3
│       ├── ...
│       ├── init-env
│       ├── README
│       ├── renew-token
│       ├── set-secrets
│       └── who-am-i
└── another-api
    └── v1.0.0
        ├── ...
        ├── init-env
        ├── README
        ├── renew-token
        ├── set-secrets
        └── who-am-i

Ovanstående inlägg publicerades 2026-04-17. Det går att prenumerera på denna webblogg. Härifrån är följande mål rekommenderade: