Skip to content
LexerLangv0.1.0

Calling other services

http_client for payment, shipping and webhook APIs; result versus error.

LexerLang
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 if

Calls#

CallEffect
.get($path[, {...}])makes a request
.post · .put · .patch · .delete · .headsame form
.header($name, $value)adds a persistent header, returns the client
.bearer($key)shorthand for Authorization: Bearer ...
OptionMeaning
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: Na time limit for this call only, in seconds

There is one body: json, form and body cannot be combined.

The response#

FieldContents
$response.statusthe status code
$response.okwhether it is 2xx
$response.bodythe body text
$response.jsonthe 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:

LexerLang
try
    $response = $api.post("/v1/payments", {json: $data})
catch($e)
    out("provider unreachable: " + $e.message)
end try

The 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#

LimitValueWhy
Time30 s (default)a slow provider should not lock up the page
Body32 MBthe other side should not fill memory
Redirects10so it cannot loop
Schemehttp, https onlyfile:// 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:

LexerLang
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.

Next#

Databases.