Go REST

PHP (cURL + Guzzle)

php-curl walkthrough with proper option setting, plus the Guzzle equivalent for production code.

PHP has two reasonable HTTP clients: the built-incurl extension (always available, low-level) and Guzzle (Composer dependency, friendlier API). Both call the Go REST API the same way: bearer token in theAuthorization header, JSON body, JSON response. This guide walks through cURL first because it works on any PHP install, then shows the Guzzle equivalent for projects that already pull in Composer.

Setup

Put the token in an environment variable so it never ends up in source control. PHP reads env viagetenv(). Simple and reliable.

<?php
// Requires PHP 8 or newer (uses the throw-expression syntax).

const API   = "https://gorest.co.in/public/v2";
$token = getenv("GOREST_TOKEN") ?: throw new RuntimeException("Set GOREST_TOKEN");

If you are on PHP 7, use the longer form instead, since the?: throw new expression is PHP 8+:

<?php
// PHP 7 alternative

const API = "https://gorest.co.in/public/v2";
$token = getenv("GOREST_TOKEN");
if (!$token) {
    throw new RuntimeException("Set GOREST_TOKEN");
}

A small wrapper

Defining a single function for every API call cleans up the rest of your code. This one returns both the status code and the decoded body so callers can branch on either:

function gorest(string $method, string $path, ?array $body = null): array {
    global $token;

    $ch = curl_init(API . $path);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST  => $method,
        CURLOPT_HTTPHEADER     => [
            "Authorization: Bearer $token",
            "Accept: application/json",
            "Content-Type: application/json",
        ],
        CURLOPT_TIMEOUT        => 15,
    ]);

    if ($body !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
    }

    $raw    = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error  = $raw === false ? curl_error($ch) : null;
    curl_close($ch);

    if ($raw === false) {
        throw new RuntimeException("cURL error: $error");
    }

    return [
        "status" => $status,
        "body"   => $raw === "" ? null : json_decode($raw, true),
    ];
}

List, fetch, write

$r = gorest("GET", "/users?status=active&page=1");
if ($r["status"] !== 200) {
    throw new RuntimeException("List users -> " . $r["status"]);
}
foreach ($r["body"] as $user) {
    echo $user["email"] . PHP_EOL;
}

Create, update, delete

The PHP cURL extension handles the body viaCURLOPT_POSTFIELDS. When you pass a JSON-encoded string and the right Content-Type, the API treats it the same as a real JSON request.

// Create
$r = gorest("POST", "/users", [
    "name"   => "Avani Iyer",
    "email"  => "avani-" . time() . "@example.com",
    "gender" => "female",
    "status" => "active",
]);
if ($r["status"] !== 201) {
    throw new RuntimeException("Create -> " . $r["status"]);
}
$userId = $r["body"]["id"];

// Update
gorest("PATCH", "/users/$userId", ["status" => "inactive"]);

// Delete
$r = gorest("DELETE", "/users/$userId");
assert($r["status"] === 204);

Validation errors come back as 422 with field-level messages. Always show them next to the offending input rather than as a generic "request failed":

$r = gorest("POST", "/users", ["name" => "x"]);
if ($r["status"] === 422) {
    foreach ($r["body"] as $err) {
        echo $err["field"] . ": " . $err["message"] . PHP_EOL;
    }
}

Pagination

Pagination metadata lives in response headers. cURL gives you headers via a header callback (CURLOPT_HEADERFUNCTION); for brevity, the pattern below relies on the empty-batch stop condition instead. In production code, capture theX-Pagination-Pages header for accurate looping:

function each_user(array $filters = []): Generator {
    $page = 1;
    while (true) {
        $query = http_build_query(array_merge($filters, ["page" => $page]));
        $r = gorest("GET", "/users?$query");
        if ($r["status"] !== 200) {
            throw new RuntimeException("List -> " . $r["status"]);
        }
        if ($r["body"] === []) return;
        foreach ($r["body"] as $u) yield $u;
        // Caller-side: read X-Pagination-Pages from a real header callback.
        // For brevity, this loop relies on the empty-array stop condition.
        $page += 1;
        if ($page > 1000) return; // safety
    }
}

foreach (each_user(["status" => "active"]) as $u) {
    echo $u["email"] . PHP_EOL;
}

Same calls in Guzzle

If your project already uses Composer, Guzzle removes most of the cURL boilerplate. JSON encoding, response decoding, and exception-based error handling are all built in.

use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;

$client = new Client([
    "base_uri" => "https://gorest.co.in/public/v2/",
    "headers"  => [
        "Authorization" => "Bearer " . getenv("GOREST_TOKEN"),
        "Accept"        => "application/json",
    ],
    "timeout"  => 15.0,
]);

$res  = $client->get("users", ["query" => ["status" => "active"]]);
$rows = json_decode($res->getBody(), true);

try {
    $client->post("users", ["json" => ["name" => "x"]]);
} catch (ClientException $e) {
    if ($e->getResponse()->getStatusCode() === 422) {
        $errors = json_decode($e->getResponse()->getBody(), true);
        // [{ field: "...", message: "..." }, ...]
    }
}

Tips

Related guides

Keep going

Back to all guides Try it in the console