Overview: The Anatomy of a Modern Office-Sharing API Building a robust backend requires more than just making the code work; it requires a commitment to long-term maintainability and security. In this session, we focus on the evolution of Ergodnc, an Airbnb-like platform specifically designed for ergonomic remote workspaces. The goal isn't just to store data, but to refine how that data is presented and secured. We address critical architectural decisions: shifting from generic polymorphic types to aliased maps, optimizing database queries for geographical distance, and implementing a strict validation layer for office creation. By the end of this walkthrough, the application will handle authenticated requests with Laravel%20Sanctum, enforce verified email status, and provide clean, filtered JSON responses that hide sensitive internal metadata. This methodical approach ensures that the API is not only functional but follows industry-standard best practices for scalability and developer experience. Prerequisites: Essential Toolkit To follow this tutorial, you should be comfortable with the following technologies and concepts: - **PHP 8.x**: Familiarity with modern PHP syntax, including anonymous functions and array destructuring. - **Laravel Framework**: Understanding of Routing, Controllers, Eloquent Relationships, and Migrations. - **RESTful Principles**: Knowledge of HTTP methods (POST, GET) and status codes (201 Created, 403 Forbidden). - **Testing Fundamentals**: Basic experience with PHPUnit or Laravel's testing suite for asserting database states and JSON structures. Key Libraries & Tools - Laravel%20Sanctum: A lightweight authentication system for SPAs and mobile APIs. We use it here to manage token-based authorization and "abilities." - Eloquent%20ORM: The database mapper that allows us to interact with our tables using expressive PHP syntax. - API%20Resources: A transformation layer that sits between your Eloquent models and the JSON responses returned to your users. - Artisan%20Test: A streamlined command-line tool (driven by Nuno%20Maduro) for running test suites with beautiful output. Refined Relationships with Custom Polymorphic Mapping By default, Laravel stores the fully qualified class name (e.g., `App\Models\Office`) in the `morph_type` column of your database. This is a mess for long-term maintenance. If you ever rename your model or move it to a different namespace, your database links break. We fix this in the `AppServiceProvider` using `Relation::enforceMorphMap`. By aliasing `App\Models\Office` to simply `office`, we keep the database clean and decouple the data from the physical code structure. ```python // AppServiceProvider.php public function boot() { Relation::enforceMorphMap([ 'office' => \App\Models\Office::class, 'user' => \App\Models\User::class, ]); } ``` Enforcing the map is a best practice. If you forget to add a new model to this list, Laravel will throw an exception during development, preventing silent failures in production. This ensures your polymorphic relationships (like images or tags attached to an office) remain consistent and readable. Advanced API Resource Configuration Returning a model directly from a controller is risky. It often leaks sensitive columns like `email_verified_at` or internal timestamps. We utilize API%20Resources to create a custom view of our data. In the `OfficeResource`, we want to hide internal IDs and timestamps while ensuring that nested relationships—like the office owner or tags—use their own refined resources. This creates a recursive cleaning process for our JSON output. ```python // OfficeResource.php public function toArray($request) { return array_merge(array_diff_key($this->resource->toArray(), array_flip([ 'user_id', 'created_at', 'updated_at', 'deleted_at' ])), [ 'user' => UserResource::make($this->user), 'images' => ImageResource::collection($this->images), 'tags' => TagResource::collection($this->tags), ]); } ``` Using `array_diff_key` allows us to exclude specific internal attributes while maintaining the rest of the dynamic model data. This ensures that the user only sees what they need to see, reducing payload size and improving security. Securing the Create Office Endpoint Creating an office is a high-privilege action. We protect the route using a combination of Sanctum guards and the `verified` middleware. This ensures the user is who they say they are and that they have confirmed their email address. Inside the `OfficeController@create`, we perform strict validation. One key decision here is the use of the `validator` helper instead of Form%20Requests. While Form Requests are popular, placing the validation logic directly in the method (or a nearby dedicated validator) can improve code legibility by making the data requirements explicit to anyone reading the controller. ```python // OfficeController.php public function create(Request $request) { $attributes = validator($request->all(), [ 'title' => ['required', 'string'], 'description' => ['required', 'string'], 'lat' => ['required', 'numeric'], 'lng' => ['required', 'numeric'], 'address_line1' => ['required', 'string'], 'price_per_day' => ['required', 'integer', 'min:100'], 'tags' => ['array'], 'tags.*' => ['integer', 'exists:tags,id'], ])->validate(); // Authorization check for Sanctum tokens if ($request->user()->tokenCan('office:create')) { // proceed with creation } $office = $request->user()->offices()->create(Arr::except($attributes, ['tags'])); $office->tags()->sync($attributes['tags'] ?? []); return OfficeResource::make($office); } ``` We use `$request->user()->offices()->create()` to automatically associate the new office with the authenticated user. This pattern is safer than manually passing a `user_id`, as it relies on the underlying Eloquent relationship to handle the foreign key assignment. Syntax Notes: Practical Patterns - **Order By Raw**: When sorting by geographical distance, we don't always want to expose the raw distance calculation in the JSON response. By using `orderByRaw`, we can sort the results in SQL without including the computed distance column in the final object array. - **Token Abilities**: Sanctum's `tokenCan` method is essential for granular API control. It allows us to distinguish between a user logged in through a full-access session and an API token that might only have permission to "read" but not "create." - **Syncing Relationships**: The `sync()` method on a Many-to-Many relationship (like tags) is a lifesaver. It automatically handles adding new tags and removing old ones in a single operation, keeping the pivot table perfectly aligned with the request data. Tips & Gotchas: Lessons from the Field 1. **Trust the Framework**: Don't waste time writing tests that verify if `required` validation works or if the `auth` middleware blocks guests. Laravel is already heavily tested. Focus your tests on your custom business logic, such as whether an office is correctly assigned to the user who created it. 2. **Sanctum Transient Tokens**: A common point of confusion is why `tokenCan` returns `true` even when no token is present. This happens because Sanctum treats first-party session-authenticated requests as having all abilities. If you need to test specific scope failures, you must explicitly generate a limited token in your test. 3. **Validation Inconsistency**: Be careful when asserting JSON paths in tests. Some Laravel test methods expect the path first, others expect the value first. Always check the method signature to avoid "false pass" scenarios where your test isn't actually asserting anything. 4. **Polymorphic Errors**: If you encounter a "No morph map defined" error, it usually means you've strictly enforced the map but missed an entry. Always add your `User` and `Token` models to the map if you are using packages like Sanctum that rely on polymorphic relations.
Eloquent%20ORM
Products
Sep 2021 • 1 videos
High activity month for Eloquent%20ORM. Laravel among the most active voices, with 1 videos across 1 sources.
Sep 2021
- Sep 16, 2021