Blog about Web Programming and Electronics
💬 👤
back Back to blog
Programming

JSON Tutorial: Connecting JavaScript Fetch API and PHP REST Backend

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.

  1. Client Request: JavaScript issues an asynchronous HTTP request (GET or POST) using fetch() targeting a specific backend endpoint.
  2. Server Processing: The PHP script receives the payload, validates parameters, runs business queries, and constructs a response array.
  3. JSON Serialization: PHP serializes the response array using json_encode() and returns it with a Content-Type: application/json header.
  4. 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.
  1. Raw Input Stream: Always read JSON payloads via file_get_contents('php://input') as superglobal $_POST only populates for standard HTML form data.
  2. Preserve UTF-8 Characters: Pass the JSON_UNESCAPED_UNICODE flag to json_encode() to prevent international and accented characters from being escaped.
back Back to blog