PHP LogoAPI Development (RESTful API)

API (Application Programming Interface) Development involves creating a set of definitions and protocols for building and integrating application software. It allows different software systems to communicate and interact with each other, exposing specific functionalities while abstracting the underlying implementation.

RESTful API (Representational State Transfer API):
REST is an architectural style for designing networked applications. A RESTful API is an API that adheres to the constraints of the REST architectural style. It treats server-side objects as 'resources' that can be manipulated (created, retrieved, updated, deleted) using a standardized, stateless set of operations, primarily leveraging HTTP methods.

Key Principles of RESTful APIs:
1. Client-Server Architecture: There's a clear separation between the client (front-end application, mobile app) and the server (back-end API). This separation allows independent development and scaling.
2. Statelessness: Each request from a client to the server must contain all the information needed to understand the request. The server should not store any client context between requests; each request is an atomic, self-contained transaction.
3. Cacheability: Responses from the server should explicitly or implicitly define themselves as cacheable or non-cacheable. This helps prevent clients from making unnecessary requests and improves performance.
4. Uniform Interface: This is a fundamental constraint that simplifies the overall system architecture. It typically involves:
* Resource Identification: Resources are identified by URIs (Uniform Resource Identifiers), e.g., `/users`, `/products/123`.
* Resource Manipulation through Representations: When a client holds a representation of a resource, it has enough information to modify or delete the resource on the server, given proper authorization.
* Self-descriptive Messages: Each message includes enough information to describe how to process it.
* Hypermedia as the Engine of Application State (HATEOAS): Clients navigate the API by following links provided within responses, rather than having hardcoded URIs.
5. Layered System: A client cannot ordinarily tell whether it is connected directly to the end server, or to an intermediary (like a proxy or load balancer). This allows for system flexibility and scalability.

HTTP Methods (Verbs) used in REST:
RESTful APIs heavily rely on standard HTTP methods to perform CRUD (Create, Read, Update, Delete) operations on resources:
* GET: Retrieves data from the specified resource. It should be safe (not alter server state) and idempotent (multiple identical requests have the same effect as a single one).
* POST: Submits data to the specified resource, often resulting in a change in state or the creation of a new resource. Not idempotent.
* PUT: Replaces all current representations of the target resource with the uploaded content. Idempotent.
* DELETE: Deletes the specified resource. Idempotent.
* PATCH: Applies partial modifications to a resource. Not necessarily idempotent.

HTTP Status Codes: Responses from a RESTful API always include an HTTP status code, indicating the success or failure of the request and providing more context (e.g., `200 OK`, `201 Created`, `404 Not Found`, `500 Internal Server Error`).

Data Format: The most common data format for exchanging information in RESTful APIs is JSON (JavaScript Object Notation), due to its lightweight nature, human-readability, and ease of parsing in most programming languages. XML is also a valid, though less common, option.

Authentication and Authorization: While not a direct part of REST principles, securing a RESTful API is crucial. Common methods include API Keys, OAuth 2.0, and JWT (JSON Web Tokens).

Example Code

<?php

// Set Content-Type header for JSON responses
header("Content-Type: application/json");

// Define the data storage file (for simplicity, using a JSON file instead of a DB)
$dataFilePath = 'items.json';

// --- Helper Functions ---

// Read all items from the JSON file
function readItems($filePath) {
    if (!file_exists($filePath) || filesize($filePath) == 0) {
        return [];
    }
    $json = file_get_contents($filePath);
    return json_decode($json, true) ?: [];
}

// Write items to the JSON file
function writeItems($filePath, $items) {
    file_put_contents($filePath, json_encode($items, JSON_PRETTY_PRINT));
}

// Generate a unique ID for new items
function generateId($items) {
    return empty($items) ? 1 : max(array_column($items, 'id')) + 1;
}

// --- Main API Logic ---

// Get the HTTP method and request URI components
$method = $_SERVER['REQUEST_METHOD'];
// Example URI: /api.php/items/1
// This simplistic routing assumes `api.php` is accessed directly and path info is used.
$requestUri = explode('/', trim($_SERVER['REQUEST_URI'], '/'));
$scriptName = basename($_SERVER['SCRIPT_NAME']);

// Find the base position of the script name in the URI parts
$scriptIndex = array_search($scriptName, $requestUri);
if ($scriptIndex !== false) {
    $requestUri = array_slice($requestUri, $scriptIndex + 1);
}

$resource = isset($requestUri[0]) ? $requestUri[0] : ''; // e.g., 'items'
$id = isset($requestUri[1]) && is_numeric($requestUri[1]) ? (int)$requestUri[1] : null; // e.g., '1'

// Simulate routing for '/items' resource
if ($resource !== 'items') {
    http_response_code(404);
    echo json_encode(['message' => 'Resource not found']);
    exit();
}

$items = readItems($dataFilePath);

switch ($method) {
    case 'GET':
        if ($id !== null) {
            // GET /items/{id} - Retrieve a single item
            $item = array_filter($items, function($item) use ($id) {
                return $item['id'] == $id;
            });
            $item = reset($item); // Get the first (and only) matched item

            if ($item) {
                http_response_code(200);
                echo json_encode($item);
            } else {
                http_response_code(404);
                echo json_encode(['message' => 'Item not found']);
            }
        } else {
            // GET /items - Retrieve all items
            http_response_code(200);
            echo json_encode($items);
        }
        break;

    case 'POST':
        // POST /items - Create a new item
        $data = json_decode(file_get_contents('php://input'), true);

        if (!isset($data['name']) || !isset($data['description'])) {
            http_response_code(400);
            echo json_encode(['message' => 'Missing required fields (name, description)']);
            exit();
        }

        $newItem = [
            'id' => generateId($items),
            'name' => $data['name'],
            'description' => $data['description'],
            'created_at' => date('Y-m-d H:i:s')
        ];

        $items[] = $newItem;
        writeItems($dataFilePath, $items);

        http_response_code(201); // Created
        echo json_encode($newItem);
        break;

    case 'PUT':
        // PUT /items/{id} - Update an existing item
        if ($id === null) {
            http_response_code(400);
            echo json_encode(['message' => 'Item ID is required for PUT request']);
            exit();
        }

        $data = json_decode(file_get_contents('php://input'), true);
        $found = false;

        foreach ($items as &$item) {
            if ($item['id'] == $id) {
                $item['name'] = $data['name'] ?? $item['name'];
                $item['description'] = $data['description'] ?? $item['description'];
                $item['updated_at'] = date('Y-m-d H:i:s');
                $found = true;
                break;
            }
        }

        if ($found) {
            writeItems($dataFilePath, $items);
            http_response_code(200);
            echo json_encode(['message' => 'Item updated successfully', 'item' => $item]);
        } else {
            http_response_code(404);
            echo json_encode(['message' => 'Item not found']);
        }
        break;

    case 'DELETE':
        // DELETE /items/{id} - Delete an item
        if ($id === null) {
            http_response_code(400);
            echo json_encode(['message' => 'Item ID is required for DELETE request']);
            exit();
        }

        $initialCount = count($items);
        $items = array_filter($items, function($item) use ($id) {
            return $item['id'] != $id;
        });
        $items = array_values($items); // Re-index array after filtering

        if (count($items) < $initialCount) {
            writeItems($dataFilePath, $items);
            http_response_code(200); // Or 204 No Content for successful deletion without content
            echo json_encode(['message' => 'Item deleted successfully']);
        } else {
            http_response_code(404);
            echo json_encode(['message' => 'Item not found']);
        }
        break;

    default:
        // Method Not Allowed
        http_response_code(405);
        echo json_encode(['message' => 'Method Not Allowed']);
        break;
}

?>