first php projects

JSON API

Expose part of the product catalog as JSON. Reuse the repository rather than building a second data-access path. The API is a new HTTP representation of the same application data.

Start With Read Endpoints

Add:

GET /api/products
GET /api/products/{id}

Return an explicit content type and stable shapes:

PHP example
<?php

declare(strict_types=1);

function jsonResponse(array $payload, int $status = 200): never
{
    http_response_code($status);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($payload, JSON_THROW_ON_ERROR);
    exit;
}

For a missing product, return a public error such as:

{"error":{"code":"product_not_found","message":"Product not found."}}

Do not expose exception text, SQL, stack traces, or internal filenames.

Add One Write Endpoint

Add POST /api/products after reads work. Decode with exceptions, validate the decoded shape, authorize the request, insert through the repository, and return 201 Created.

PHP example
<?php

declare(strict_types=1);

try {
    $payload = json_decode($rawBody, true, flags: JSON_THROW_ON_ERROR);
} catch (JsonException) {
    jsonResponse([
        'error' => ['code' => 'invalid_json', 'message' => 'Request body is not valid JSON.'],
    ], 400);
}

Malformed JSON and well-formed but invalid product data are different failures. Use a consistent validation error shape for the second case.

Keep Lists Bounded

Limit the list endpoint and make pagination visible before the catalog grows. Add authentication or a deliberate public/private decision for writes. Apply rate limiting where abuse would be costly.

Verify As A Client

Use curl to check list, found, missing, malformed JSON, validation failure, unauthorized create, and successful create cases.

Practice

Practice: Build A Product JSON API

Implement and verify the small JSON product API from the lesson using the existing repository.

Requirements

  • Expose list, find, and create endpoints.
  • Return JSON with an explicit content type.
  • Use stable error shapes and appropriate HTTP status codes.
  • Validate input and authorise writes.
  • Handle malformed JSON deliberately.
  • Do not leak exceptions or SQL in API responses.
  • Keep pagination and rate limits visible for list endpoints.

Record the curl command, status code, and JSON shape for list, found, missing, malformed JSON, validation failure, unauthorized create, and successful create cases.

Show solution
  1. Checks authorization.
  2. Reads the raw request body.
  3. Decodes JSON with JSON_THROW_ON_ERROR.
  4. Validates name, price_cents, and status.
  5. Inserts through ProductRepository.
  6. Returns the created resource with 201.

Use one stable error shape:

{"error":{"code":"validation_failed","message":"Product data is invalid.","fields":{"name":"Enter a name."}}}

Run the required curl cases and compare both the HTTP status and JSON body. A client should never need to parse raw PHP errors.