Home >Backend Development >PHP Tutorial >Build a REST API from Scratch: Implementation
This tutorial's first part established our API's foundational layers: server setup, authentication, JSON handling, error management, and initial routes. Crucially, we defined resources and actions in the README. Now, let's build upon this foundation by implementing those resources.
Key Concepts:
Contact Management: Creation and Updates
Starting with contact creation, REST best practices dictate returning a resource representation after creation or update. While the database interaction in this example is simplified for clarity, a production API would leverage a more robust ORM/Model and validation library.
<code class="language-php">$app->post( '/contacts', function () use ($app, $log) { $body = $app->request()->getBody(); $errors = $app->validateContact($body); if (empty($errors)) { $contact = \ORM::for_table('contacts')->create(); if (isset($body['notes'])) { $notes = $body['notes']; unset($body['notes']); } $contact->set($body); if ($contact->save()) { if (!empty($notes)) { $contactNotes = []; foreach ($notes as $item) { $item['contact_id'] = $contact->id; $note = \ORM::for_table('notes')->create(); $note->set($item); if ($note->save()) { $contactNotes[] = $note->asArray(); } } } $output = $contact->asArray(); if (!empty($contactNotes)) { $output['notes'] = $contactNotes; } echo json_encode($output, JSON_PRETTY_PRINT); } else { throw new Exception("Unable to save contact"); } } else { throw new ValidationException("Invalid data", 0, $errors); } } );</code>
This POST /contacts
endpoint processes the request body, validates data, creates a contact record, handles associated notes (if provided), and returns a JSON representation of the created contact. Update operations (PUT
and PATCH
) follow a similar pattern, checking for contact and note existence before processing. The PUT
and PATCH
methods are mapped to the same code for efficiency:
<code class="language-php">$app->map( '/contacts/:id', function ($id) use ($app, $log) { // Update code here... })->via('PUT', 'PATCH');</code>
Contact Listing and Filtering
Basic contact listing is straightforward:
<code class="language-php">$app->get( '/contacts', function () use ($app, $log) { $contacts = \ORM::forTable('contacts')->findArray(); echo json_encode($contacts, JSON_PRETTY_PRINT); } );</code>
However, a robust API supports advanced querying: /api/v1/contacts?fields=firstname,email&sort=-email&firstname=Viola&q=vitae
This example demonstrates filtering by firstname
, searching within firstname
or email
using q
, sorting by email
, and selecting specific fields. The implementation involves sanitizing inputs and dynamically building the database query:
<code class="language-php">$app->post( '/contacts', function () use ($app, $log) { $body = $app->request()->getBody(); $errors = $app->validateContact($body); if (empty($errors)) { $contact = \ORM::for_table('contacts')->create(); if (isset($body['notes'])) { $notes = $body['notes']; unset($body['notes']); } $contact->set($body); if ($contact->save()) { if (!empty($notes)) { $contactNotes = []; foreach ($notes as $item) { $item['contact_id'] = $contact->id; $note = \ORM::for_table('notes')->create(); $note->set($item); if ($note->save()) { $contactNotes[] = $note->asArray(); } } } $output = $contact->asArray(); if (!empty($contactNotes)) { $output['notes'] = $contactNotes; } echo json_encode($output, JSON_PRETTY_PRINT); } else { throw new Exception("Unable to save contact"); } } else { throw new ValidationException("Invalid data", 0, $errors); } } );</code>
This section would include the detailed code for handling fields
, sort
, page
, per_page
parameters, building the query, and managing pagination including the generation of Link
headers.
Contact Details and Embedded Resources
Retrieving individual contact details is simple:
<code class="language-php">$app->map( '/contacts/:id', function ($id) use ($app, $log) { // Update code here... })->via('PUT', 'PATCH');</code>
To improve efficiency, embedded resources (e.g., notes) can be fetched using query parameters like /api/v1/contacts/1?embed=notes
. The code would be modified to include an additional query for notes if the embed
parameter is present.
Caching and Rate Limiting
Caching and rate limiting are implemented using middleware, enhancing performance and API protection. The middleware code (for both caching and rate limiting) would be similar to the original example, handling cache hits/misses, ETag generation, expiration, and rate limit checks, including the appropriate HTTP headers.
Further Development
This enhanced API provides a solid foundation. Future improvements include migrating to a more robust ORM/Model, integrating a dedicated validation library, exploring alternative storage solutions, implementing API discovery (e.g., Swagger), and creating a comprehensive test suite. The complete source code (as mentioned in the original) would provide the full implementation details.
The above is the detailed content of Build a REST API from Scratch: Implementation. For more information, please follow other related articles on the PHP Chinese website!