Modern web applications rely heavily on asynchronous communication between the client browser and backend servers, exchanging data formatted in JSON without triggering full page reloads. In this comprehensive guide, we cover the end-to-end integration lifecycle: building a robust PHP REST API backend alongside executing GET and POST requests using the JavaScript Fetch API.
How Client-Server Communication Works
Data exchange between client-side JavaScript and the backend follows a structured four-stage cycle.
- Client Request: JavaScript issues an asynchronous HTTP request (GET or POST) using
fetch()targeting a specific backend endpoint. - Server Processing: The PHP script receives the payload, validates parameters, runs business queries, and constructs a response array.
- JSON Serialization: PHP serializes the response array using
json_encode()and returns it with aContent-Type: application/jsonheader. - Browser Parsing: JavaScript parses the JSON payload into native objects via
response.json(), updating the DOM dynamically.
Building the PHP API Backend (api/naprave.php)
The PHP script below handles both GET queries for retrieving records and incoming POST requests for creating new entries.
<?php
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header('Access-Control-Allow-Headers: Content-Type');
$method = $_SERVER['REQUEST_METHOD'];
// Mock dataset (in production, retrieved from a database query)
$deviceDatabase = [
['id' => 1, 'name' => 'Main Lighting', 'active' => true, 'updated' => '2026-08-14 10:15:00'],
['id' => 2, 'name' => 'Ventilation', 'active' => false, 'updated' => '2026-08-14 11:30:00']
];
// 1. HANDLE GET REQUESTS (Read Operations)
if ($method === 'GET') {
$response = [
'status' => 'success',
'total' => count($deviceDatabase),
'data' => $deviceDatabase
];
echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
}
// 2. HANDLE POST REQUESTS (Write Operations)
if ($method === 'POST') {
$rawPayload = file_get_contents('php://input');
$receivedData = json_decode($rawPayload, true);
if (!$receivedData || !isset($receivedData['name'])) {
http_response_code(400);
echo json_encode(['status' => 'error', 'message' => 'Invalid payload.'], JSON_UNESCAPED_UNICODE);
exit;
}
$newDevice = [
'id' => rand(10, 100),
'name' => htmlspecialchars($receivedData['name']),
'active' => isset($receivedData['active']) ? (bool)$receivedData['active'] : false,
'created' => date('Y-m-d H:i:s')
];
http_response_code(201); // 201 Created
echo json_encode(['status' => 'success', 'new_device' => $newDevice], JSON_UNESCAPED_UNICODE);
exit;
}
http_response_code(405);
echo json_encode(['status' => 'error', 'message' => 'Method not allowed.']);
?>
Consuming Endpoints with JavaScript Fetch
We use modern async / await syntax along with structured error handling to read and post JSON payloads seamlessly.
// 1. Fetching data from the server (GET Request)
async function fetchDevices() {
try {
const response = await fetch('api/naprave.php');
if (!response.ok) {
throw new Error(`Server returned status: ${response.status}`);
}
const result = await response.json();
console.log('Received payload:', result.data);
} catch (error) {
console.error('Error fetching data:', error);
}
}
// 2. Submitting new data to the server (POST Request)
async function createDevice(name, active) {
try {
const response = await fetch('api/naprave.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: name, active: active })
});
const result = await response.json();
if (!response.ok) throw new Error(result.message);
console.log('Record successfully created:', result);
} catch (error) {
console.error('Error submitting payload:', error);
}
}
HTTP Status Codes and Best Practices
Adhering to standard HTTP status codes ensures clear communication and resilient client-side error handling.
| Status Code | Meaning | Typical Use Case |
|---|---|---|
| 200 OK | Standard Success | Successful GET retrieval or record update. |
| 201 Created | Resource Created | Successfully inserted a new entity via POST. |
| 400 Bad Request | Invalid Request | Malformed JSON payload or missing mandatory parameters. |
| 404 Not Found | Not Found | Target resource ID or endpoint route does not exist. |
| 500 Server Error | Internal Server Error | Database connection failures or unhandled backend exceptions. |
- Raw Input Stream: Always read JSON payloads via
file_get_contents('php://input')as superglobal$_POSTonly populates for standard HTML form data. - Preserve UTF-8 Characters: Pass the
JSON_UNESCAPED_UNICODEflag tojson_encode()to prevent international and accented characters from being escaped.