Working with APIs

Create PHP JSON APIs and retrieve database records through focused endpoints.

Creating a Simple JSON API with PHP

In this tutorial, you will create a simple API using PHP.

The API will return JSON data when visited in a browser.

This is the same type of data format used by many real-world APIs.


Project Structure

Create a folder called:

api-demo

Inside the folder place:

api-demo
├── api.php
└── smart_security_data.json

Create the API File

Create:

api.php

Add:

<?php

header(
    "Content-Type: application/json"
);

echo file_get_contents(
    "smart_security_data.json"
);

?>

Save the file.


Understanding the Code

This line tells the browser that JSON data is being returned:

header(
    "Content-Type: application/json"
);

This line reads the JSON file:

file_get_contents(
    "smart_security_data.json"
);

This line sends the JSON data to the browser:

echo file_get_contents(
    "smart_security_data.json"
);

Test the API

Open:

http://localhost/api-demo/api.php

You should see:

{
  "homeId": "GC-HOME-014",
  "location": "Gold Coast"
}

along with the rest of the JSON data.

Test the API in a New Browser Tab

Notice that the URL now behaves like a data source.

Instead of displaying a webpage, it returns structured JSON data.

This is the same concept used by many modern APIs.

Example:

https://example.com/api/users
https://example.com/api/products
https://example.com/api/weather

Complete API File

<?php

header(
    "Content-Type: application/json"
);

echo file_get_contents(
    "smart_security_data.json"
);

?>

You have successfully created a JSON API using PHP.

Reading API Data with JavaScript

The API returns JSON data when visited in a browser.

In this tutorial, you will use JavaScript to read data from the API and display it on a webpage.


Project Structure

Your project should contain:

api-demo
├── api.php
├── index.html
└── smart_security_data.json

Create the HTML Page

Create:

index.html

Add:

<!DOCTYPE html>
<html>
<head>
    <title>API Demo</title>
</head>
<body>

<h1>API Dashboard</h1>

<div id="output"></div>

<script>

</script>

</body>
</html>

Save the file.


Read the API

Inside the <script> tags add:

fetch("api.php")
    .then(response => response.json())
    .then(data => {

        console.log(data);

    });

Save the file.


Test the API Request

Open:

http://localhost/api-demo/

Press:

F12

Open the Console tab.

You should see the JSON object displayed.

Display the Home Information

Replace:

console.log(data);

with:

document.getElementById(
    "output"
).innerHTML = `

    <p>
        <strong>Home ID:</strong>
        ${data.homeId}
    </p>

    <p>
        <strong>Location:</strong>
        ${data.location}
    </p>

`;

Refresh the page.

You should see:

Home ID: GC-HOME-014

Location: Gold Coast

Display Device Information

Replace the existing code with:

let html = `

    <h2>Devices</h2>

    <table border="1">

        <tr>
            <th>Device ID</th>
            <th>Device Type</th>
            <th>Room</th>
        </tr>

`;

data.devices.forEach(device => {

    html += `

        <tr>
            <td>${device.deviceId}</td>
            <td>${device.deviceType}</td>
            <td>${device.room}</td>
        </tr>

    `;

});

html += "</table>";

document.getElementById(
    "output"
).innerHTML = html;

Refresh the page.

You should now see a table of devices.

Why Use an API?

Previously, the data was loaded directly from:

fetch("smart_security_data.json")

Now the data is loaded from:

fetch("api.php")

This means the data can be:

The webpage does not need to know where the data comes from. It only needs the JSON returned by the API.


Complete Page

<!DOCTYPE html>
<html>
<head>
    <title>API Demo</title>
</head>
<body>

<h1>API Dashboard</h1>

<div id="output"></div>

<script>

fetch("api.php")
    .then(response => response.json())
    .then(data => {

        let html = `

            <h2>Devices</h2>

            <table border="1">

                <tr>
                    <th>Device ID</th>
                    <th>Device Type</th>
                    <th>Room</th>
                </tr>

        `;

        data.devices.forEach(device => {

            html += `

                <tr>
                    <td>${device.deviceId}</td>
                    <td>${device.deviceType}</td>
                    <td>${device.room}</td>
                </tr>

            `;

        });

        html += "</table>";

        document.getElementById(
            "output"
        ).innerHTML = html;

    });

</script>

</body>
</html>

You have successfully consumed data from an API using JavaScript.

Creating a Database-Driven API with PHP and MySQL

This tutorial creates a read-only JSON endpoint using PHP, PDO and fictional database records.

An API should return only the data needed for its stated purpose. Do not expose password hashes, session data, personal information or unnecessary database fields.

Create the endpoint

Create api/events.php:

<?php
declare(strict_types=1);

require __DIR__ . '/../includes/database.php';

header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store');

try {
    $statement = $pdo->query(
        'SELECT
            event_id,
            event_timestamp,
            device_id,
            room,
            event_type,
            severity,
            access_result
         FROM security_events
         ORDER BY event_timestamp DESC
         LIMIT 100'
    );

    $events = $statement->fetchAll();

    echo json_encode(
        [
            'ok' => true,
            'count' => count($events),
            'events' => $events
        ],
        JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES
    );
} catch (Throwable $error) {
    http_response_code(500);

    echo json_encode([
        'ok' => false,
        'error' => 'The fictional event data is unavailable.'
    ]);
}

The endpoint:

Test the response

Open the endpoint through XAMPP:

http://localhost/project/api/events.php

A successful response should have this shape:

{
  "ok": true,
  "count": 2,
  "events": [
    {
      "event_id": 14,
      "event_timestamp": "2026-06-14 20:57:06",
      "device_id": "CAM-01",
      "room": "Science Lab",
      "event_type": "failed_login",
      "severity": "medium",
      "access_result": "denied"
    }
  ]
}

The values are fictional. Your live response will reflect the current database.

Important boundary

This example is a public, read-only classroom endpoint. A production API may also require authentication, authorisation, pagination, rate limiting, audit logging and a documented privacy purpose.

Check

Creating API Endpoints for Specific Data

Focused endpoints return the smallest useful result for a particular user need. This tutorial adds filtered and summary endpoints using PDO and fictional records.

Endpoint for one severity

Create api/events-by-severity.php:

<?php
declare(strict_types=1);

require __DIR__ . '/../includes/database.php';

header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store');

$allowed = ['low', 'medium', 'high', 'critical'];
$severity = strtolower(trim($_GET['severity'] ?? ''));

if (!in_array($severity, $allowed, true)) {
    http_response_code(400);
    echo json_encode([
        'ok' => false,
        'error' => 'Choose low, medium, high or critical.'
    ]);
    exit;
}

$statement = $pdo->prepare(
    'SELECT
        event_id,
        event_timestamp,
        device_id,
        room,
        event_type,
        severity
     FROM security_events
     WHERE severity = :severity
     ORDER BY event_timestamp DESC
     LIMIT 100'
);

$statement->execute(['severity' => $severity]);
$events = $statement->fetchAll();

echo json_encode([
    'ok' => true,
    'filter' => ['severity' => $severity],
    'count' => count($events),
    'events' => $events
]);

Test it with a fictional category:

http://localhost/project/api/events-by-severity.php?severity=high

The allow-list rejects unexpected values and the prepared statement keeps the supplied value separate from the SQL.

Endpoint for summary totals

Create api/event-summary.php:

<?php
declare(strict_types=1);

require __DIR__ . '/../includes/database.php';

header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store');

$statement = $pdo->query(
    'SELECT severity, COUNT(*) AS total
     FROM security_events
     GROUP BY severity
     ORDER BY severity'
);

$rows = $statement->fetchAll();

$summary = [];

foreach ($rows as $row) {
    $summary[] = [
        'severity' => $row['severity'],
        'total' => (int) $row['total']
    ];
}

echo json_encode([
    'ok' => true,
    'summary' => $summary
]);

This endpoint returns processed information rather than every event record. It can support an accessible table or chart.

Choose endpoints from user needs

Useful endpoints might answer:

Avoid creating many endpoints that expose the same unnecessary fields.

Check