LearnContact
Lesson 5622 min read

Working with APIs

Learn how to make outbound HTTP requests from PHP with file_get_contents() and cURL, and decode JSON API responses.

Introduction

So far you have learned how to filter data, apply regex, and encode or decode JSON and XML — all skills you need to talk to the outside world. This lesson puts them together: making an outbound HTTP request from PHP to a REST API, and working with the response it sends back.

You will see two ways to do this — the simple file_get_contents() with a stream context, and the more capable cURL extension — plus how to safely decode and use the JSON response.

What You Will Learn
  • What a REST API is at a practical level.
  • How to make a simple HTTP request with file_get_contents() and a stream context.
  • How to make a more capable request using the cURL extension.
  • How to decode a JSON API response into usable PHP data.
  • How to fetch and display data from a real public API.

What Is a REST API?

A REST API is a web service that responds to HTTP requests — typically GET, POST, PUT, and DELETE — at specific URLs, and usually returns data as JSON. When your PHP script "calls an API," it is really just making an HTTP request to another server, exactly like a browser does, and reading the response body.

URL Endpoints

Each API "endpoint" is a URL that responds with data, like https://api.example.com/users/1.

HTTP Methods

GET fetches data, POST creates it, PUT/PATCH updates it, DELETE removes it.

JSON Payloads

Most modern APIs send and receive data formatted as JSON.

Authentication

Many APIs require an API key or token sent in the request headers.

Making Requests with file_get_contents()

PHP's file_get_contents() can read from a URL just as easily as a local file, as long as the "allow_url_fopen" setting is enabled (it is by default on most setups). For a simple GET request, you can call it with nothing more than the URL.

simple-get.php
<?php
$response = file_get_contents("https://jsonplaceholder.typicode.com/users/1");

if ($response === false) {
    echo "Request failed.";
} else {
    echo $response;
}
Output (abbreviated)
{"id":1,"name":"Leanne Graham","username":"Bret","email":"Sincere@april.biz", ...}

For more control — setting a timeout, custom headers, or a different HTTP method — wrap the request in a stream context using stream_context_create().

stream-context.php
<?php
$options = [
    "http" => [
        "method"  => "GET",
        "header"  => "Accept: application/json\r\n",
        "timeout" => 5,
    ],
];

$context = stream_context_create($options);
$response = file_get_contents("https://jsonplaceholder.typicode.com/users/1", false, $context);

echo $response !== false ? "Request succeeded." : "Request failed.";
Output
Request succeeded.

Making Requests with cURL

The cURL extension is more powerful and flexible than file_get_contents() — it gives you detailed control over headers, methods, timeouts, authentication, and error handling, and is the standard choice for anything beyond the simplest request.

curl-basic.php
<?php
$ch = curl_init("https://jsonplaceholder.typicode.com/users/1");

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // return the response instead of printing it
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Accept: application/json"]);

$response = curl_exec($ch);

if (curl_errno($ch)) {
    echo "cURL error: " . curl_error($ch);
} else {
    echo $response;
}

curl_close($ch);
Output (abbreviated)
{"id":1,"name":"Leanne Graham","username":"Bret","email":"Sincere@april.biz", ...}

The typical cURL pattern is always the same: curl_init() to start a session, curl_setopt() to configure it, curl_exec() to send the request, and curl_close() to clean up.

file_get_contents()

  • Simpler for a quick GET request
  • Requires allow_url_fopen enabled
  • Fewer built-in options for headers/auth
  • Good enough for basic, low-stakes requests

cURL

  • More setup, more control
  • Handles POST bodies, auth, and custom headers cleanly
  • Provides detailed error reporting via curl_errno()/curl_error()
  • The standard choice for production API integrations

Decoding the JSON Response

Whichever method you use to fetch the response, the body usually arrives as a raw JSON string. Decode it with json_decode() (covered in an earlier lesson) before working with the data as normal PHP values.

decode-response.php
<?php
$response = file_get_contents("https://jsonplaceholder.typicode.com/users/1");

$user = json_decode($response, true);

if (json_last_error() !== JSON_ERROR_NONE) {
    echo "Could not parse API response.";
} else {
    echo "Name: {$user['name']}\n";
    echo "Email: {$user['email']}";
}
Output
Name: Leanne Graham
Email: Sincere@april.biz

Example: Fetching from a Public API

Here is a complete example using cURL to fetch a short list of posts from a free placeholder API and display just the fields we care about.

fetch-posts.php
<?php
$ch = curl_init("https://jsonplaceholder.typicode.com/posts?_limit=3");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);

$response = curl_exec($ch);

if (curl_errno($ch)) {
    echo "Request failed: " . curl_error($ch);
    curl_close($ch);
    exit;
}
curl_close($ch);

$posts = json_decode($response, true);

if (json_last_error() !== JSON_ERROR_NONE) {
    echo "Could not parse response.";
    exit;
}

foreach ($posts as $post) {
    echo "#{$post['id']}: {$post['title']}\n";
}
Output
#1: sunt aut facere repellat provident occaecati excepturi optio reprehenderit
#2: qui est esse
#3: ea molestias quasi exercitationem repellat qui ipsa sit aut

Notice the pattern that will repeat across almost every API integration you write: make the request, check for a transport-level error, check for a JSON-decoding error, then use the resulting PHP array like any other data.

Common Mistakes

Avoid These Mistakes
  • Assuming a request always succeeds and skipping error checks — networks and third-party servers fail regularly.
  • Forgetting CURLOPT_RETURNTRANSFER, which causes curl_exec() to print the response directly instead of returning it.
  • Not decoding the JSON response before trying to read fields from it.
  • Making requests with no timeout set, which can leave a script hanging indefinitely if the remote server stalls.

Best Practices

  • Prefer cURL for anything beyond a trivial GET request — it handles headers, methods, and errors far more cleanly.
  • Always set a reasonable timeout so a slow or unresponsive API cannot hang your script.
  • Check both the transport-level error (curl_errno()) and the JSON-decoding error (json_last_error()) before trusting the data.
  • Never hardcode API keys directly in source files that might be committed to version control — use environment variables instead.
  • Respect API rate limits and read the documentation for the service you are integrating with.

Frequently Asked Questions

Should I use file_get_contents() or cURL for API calls?

file_get_contents() is fine for very simple GET requests, but cURL is the standard choice once you need custom headers, POST data, authentication, or detailed error handling.

Why does curl_exec() print the response instead of returning it?

By default cURL outputs the response directly. Setting CURLOPT_RETURNTRANSFER to true makes curl_exec() return the response as a string instead.

How do I send an API key with a request?

Most APIs expect the key in a header, which you can add with curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_KEY"]) or the equivalent stream context header option.

What happens if the API returns invalid JSON?

json_decode() returns null and json_last_error() reports a non-zero error code, so you should always check that before using the decoded data.

Key Takeaways

  • A REST API responds to HTTP requests at specific URLs, typically returning JSON.
  • file_get_contents() with a stream context can make simple HTTP requests with minimal setup.
  • cURL (curl_init/curl_setopt/curl_exec) offers far more control and is the standard for real API integrations.
  • Always decode JSON responses with json_decode() and check json_last_error() before using the data.
  • Always set timeouts and check for errors — external services and networks are unreliable by nature.

Summary

Calling external APIs is one of the most practical things you will do as a PHP developer — nearly every real application talks to at least one third-party service. You now know how to make requests with both file_get_contents() and cURL, and how to safely decode and use the JSON they return.

With filtering, regex, JSON, XML, and API calls behind you, you are ready to move into working with databases, starting with an introduction to MySQL.

Lesson 56 Completed
  • You understand what a REST API is at a practical level.
  • You can make an HTTP request with file_get_contents() and a stream context.
  • You can make a more capable request using cURL.
  • You can decode and safely use a JSON API response.
Next Lesson →

Introduction to MySQL