Calling other services
http_client for payment, shipping and webhook APIs; result versus error.
use http_client
$api = new http_client({
base_url: "https://api.paymentprovider.com",
timeout: 15,
headers: {Accept: "application/json"}
})
with $api
.bearer($secret_key)
.header("X-Merchant-Id", "12345")
end with
$response = $api.post("/v1/payments", {
json: {amount: 125000, currency: "TRY", installment: 1},
headers: {"Idempotency-Key": $order_no}
})
if $response.ok then
out("payment taken: " + $response.json.id)
else
out("declined (" + $response.status + "): " + $response.body)
end ifCalls#
| Call | Effect |
|---|---|
.get($path[, {...}]) | makes a request |
.post · .put · .patch · .delete · .head | same form |
.header($name, $value) | adds a persistent header, returns the client |
.bearer($key) | shorthand for Authorization: Bearer ... |
| Option | Meaning |
|---|---|
json: {...} | JSON body + application/json |
form: {...} | form body + application/x-www-form-urlencoded |
body: "..." | raw body (with content_type) |
query: {...} | adds query fields to the URL |
headers: {...} | headers for this call only |
timeout: N | a time limit for this call only, in seconds |
There is one body: json, form and body cannot be combined.
The response#
| Field | Contents |
|---|---|
$response.status | the status code |
$response.ok | whether it is 2xx |
$response.body | the body text |
$response.json | the decoded body; null if it is not JSON |
$response.headers · $response.header($name) | response headers |
$response.content_type · $response.url |
Result or error#
4xx and 5xx do not raise. Payment providers report a refusal with 400 and put the reason in the body; if an error were raised, the reason would be out of reach. You ask about the outcome with $response.ok.
If the network could not be reached at all — DNS, connection, timeout — an error is raised. There is no response there, so there can be no $response.status:
try
$response = $api.post("/v1/payments", {json: $data})
catch($e)
out("provider unreachable: " + $e.message)
end tryThe distinction answers a real question: "what did the other side say" and "I could not reach the other side" are different events and deserve different handling.
Limits#
| Limit | Value | Why |
|---|---|---|
| Time | 30 s (default) | a slow provider should not lock up the page |
| Body | 32 MB | the other side should not fill memory |
| Redirects | 10 | so it cannot loop |
| Scheme | http, https only | file:// would be a door onto the disk |
A newline in a header value is rejected; if it passed, a header could be injected into the request.
Configuration#
Secrets are not written in code:
use env_parser
$env = new env_parser(path.pwd + "/.env")
$key = $env.require("STRIPE_SECRET") # error if missing
$port = $env.get("PORT", 3000)require catches a missing secret at startup. Giving a default with get would mean a missing key goes unnoticed until the first payment attempt.