APIs
advancedPart of PHP Data & APIs
Theory
An API (Application Programming Interface) allows different software systems to communicate with each other. In web development, REST APIs are the most common type, allowing clients to interact with servers using standard HTTP methods.
What is an API?
An API defines a set of rules and protocols for building and interacting with software applications. A REST API (Representational State Transfer) uses HTTP requests to perform CRUD operations on resources:
- GET — Retrieve a resource or collection
- POST — Create a new resource
- PUT / PATCH — Update an existing resource
- DELETE — Remove a resource
HTTP Methods
| Method | Purpose | Idempotent | Safe | |--------|---------|:----------:|:----:| | GET | Read data | ✓ | ✓ | | POST | Create new resource | ✗ | ✗ | | PUT | Replace entire resource | ✓ | ✗ | | PATCH | Partially update resource | ✓ | ✗ | | DELETE | Remove resource | ✓ | ✗ |
Idempotent means multiple identical requests have the same effect as one request. Safe means the request doesn't modify any data.
JSON in PHP
json_encode — converts PHP data to JSON:
<?php
$data = [
'id' => 1,
'name' => 'Alice',
'email' => 'alice@example.com',
'roles' => ['admin', 'editor'],
'is_active' => true,
];
$json = json_encode($data);
echo $json;
// {"id":1,"name":"Alice","email":"alice@example.com","roles":["admin","editor"],"is_active":true}
// Pretty print
$json = json_encode($data, JSON_PRETTY_PRINT);
// With specific options
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
?>json_decode — converts JSON to PHP data:
<?php
$json = '{"id":1,"name":"Alice","email":"alice@example.com"}';
// Decode to associative array (default)
$data = json_decode($json, true);
echo $data['name']; // Alice
// Decode to object
$obj = json_decode($json);
echo $obj->name; // Alice
// Handle errors
$decoded = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
echo 'JSON decode error: ' . json_last_error_msg();
}
?>Creating a Simple REST API
A basic PHP REST API structure:
Consuming External APIs
file_get_contents with stream context:
<?php
$url = 'https://api.github.com/users/octocat';
$options = [
'http' => [
'method' => 'GET',
'header' => [
'User-Agent: PHP',
'Accept: application/json',
],
],
];
$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
if ($response === false) {
echo 'API request failed';
} else {
$data = json_decode($response, true);
echo 'Name: ' . $data['login'];
echo 'Repos: ' . $data['public_repos'];
}
?>cURL (more powerful, recommended for complex requests):
<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://api.github.com/users/octocat',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'User-Agent: PHP',
'Accept: application/json',
],
CURLOPT_TIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => true,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
echo 'cURL error: ' . $error;
} elseif ($httpCode >= 400) {
echo "HTTP error: $httpCode";
} else {
$data = json_decode($response, true);
print_r($data);
}
?>POST request with cURL:
<?php
$postData = json_encode([
'title' => 'New Post',
'body' => 'This is the body',
'userId' => 1,
]);
$ch = curl_init('https://jsonplaceholder.typicode.com/posts');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postData,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Content-Length: ' . strlen($postData),
],
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "Status: $httpCode\n";
echo $response;
?>API Authentication
API Key Authentication:
<?php
// Server-side: validate API key
function authenticateRequest(): bool {
$apiKey = $_SERVER['HTTP_X_API_KEY'] ?? '';
// In production, check against database
$validKeys = [
'abc123' => ['user' => 'Alice', 'role' => 'admin'],
'def456' => ['user' => 'Bob', 'role' => 'user'],
];
if (isset($validKeys[$apiKey])) {
$_SESSION['api_user'] = $validKeys[$apiKey];
return true;
}
return false;
}
// Middleware
if (!authenticateRequest()) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
}
?>Basic Authentication:
<?php
function authenticateBasic(): ?array {
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="API"');
http_response_code(401);
echo json_encode(['error' => 'Authentication required']);
exit;
}
$username = $_SERVER['PHP_AUTH_USER'];
$password = $_SERVER['PHP_AUTH_PW'];
// Verify against database
if ($username === 'admin' && $password === 'secret') {
return ['id' => 1, 'username' => $username];
}
http_response_code(401);
echo json_encode(['error' => 'Invalid credentials']);
exit;
}
?>Bearer Token Authentication:
<?php
function authenticateBearer(): ?array {
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if (!preg_match('/^Bearer\s+(.+)$/', $authHeader, $matches)) {
http_response_code(401);
echo json_encode(['error' => 'Bearer token required']);
exit;
}
$token = $matches[1];
// Verify token (JWT or database lookup)
if ($token === 'valid-token-123') {
return ['id' => 1, 'username' => 'Alice'];
}
http_response_code(401);
echo json_encode(['error' => 'Invalid token']);
exit;
}
?>When consuming external APIs, always implement error handling, timeouts, and rate limiting. Never make API calls synchronously in a web request without considering the performance impact.
Practical Examples
Always validate and sanitize input before processing it in your API. Never trust client data. Use a whitelist approach for fields that can be updated.
Exercises
Build a Quotes API
Create a REST API that serves random quotes. Implement: GET /api/quotes (returns all quotes), GET /api/quotes/random (returns random quote), POST /api/quotes (adds a new quote), GET /api/quotes/{id} (returns a specific quote).
Expected Output:
A fully functional REST API that can be tested with curl: curl http://localhost/api/quotes, curl http://localhost/api/quotes/random, etc.Weather Dashboard with External API
Create a PHP page that fetches weather data from the OpenWeatherMap API (or a mock) and displays it. Implement: city search, current weather display (temperature, conditions, humidity, wind), and error handling for API failures.
Expected Output:
Current weather information for a searched city, or an appropriate error message if the city is not found or the API call fails.Full REST API with Database and JWT Auth
Build a complete REST API with database persistence and JWT (JSON Web Token) authentication. Include: user registration, user login (returns JWT), protected CRUD endpoints for notes, and token validation middleware.
Expected Output:
A secure REST API with JWT authentication: users can register, log in, and manage their own notes. Unauthenticated requests return 401. Users cannot access other users' notes.Mini Quiz
Mini Quiz
Mini Project
Mini Project: GitHub Portfolio API Aggregator
Build a PHP application that aggregates data from the GitHub API to create a developer portfolio page. Fetch user repos, languages, commits, and display them in a clean dashboard.
Requirements:
Bonus Challenge
Add a comparison feature to compare two GitHub profiles side by side. Generate a simple contribution heatmap using the events API.