Diving into API development with Laravel

Diving into API development with Laravel

So far, I've been working with Laravel Monoliths. A monolith in Laravel is a software architecture where the entire application exists within a single codebase. This includes all the business logic, database interactions, client-side handling, and more.

Monolithic software is supposed to be self-contained, meaning all its components are interconnected and work together within a single system. One use case might be building a simple brochure website.

But in the real world (and many job ads), there is much demand for understanding how APIs are used in Laravel Development.

How API systems differ

A common challenge that many enterprises grapple with is the need for a unified system capable of consolidating data from multiple and disparate codebases. There could be many factors contributing to the incompatibility or inaccessibility of these individual codebases - they might be externally maintained and written in completely different languages, among other things.

In a scenario where the back-end operations are handled by Laravel, while the front-end relies on a Vue codebase, it becomes vital to establish a connection between these codebases, enabling them to interact seamlessly.

In such cases, an Application Programming Interface (API) is a widely accepted solution. API-based systems predominantly employ JSON as their primary data exchange format. Its attributes of being lightweight, easily readable, and universally compatible make it an ideal choice.

7 Key points newbies should remember about API development in Laravel

I've been having some training recently on API development in Laravel in the practical sense, where I have learned how to approach an API design and here are 7 of the key points I have learned so far in how developing for an API endpoint differs from the monoliths I have mostly covered to date.

💡
I have continued to work with my Gallery project for these examples as seen in development in my recent PEST Testing post.

1) API's have their own file for routes

Already built into core Laravel, in the Routes directory, is Api.php.
Technically, you can put your routes in the web.php file but it's not convention to do so. API routes should be separate from those designed to be accessed via a browser.

Route::post('login', LoginController::class);

Route::middleware('auth:sanctum')->group(function(){

    Route::apiResource('albums', AlbumsController::class, [
        'as' => 'api'
    ]);
});

Notice the use of 'as' => 'api' on the apiResource route, this is helpful if the same structure is used in the web.php file and allows the routes keep the some naming convention while being easily identified as either API or web.

Notice also how the apiResource route is in the 'auth:sanctum' middleware group. This is for API route that must be accesible only for logged in users.

2) An API does not have views

Working with an API is entirely a backend exercise. Nothing can be called from the browser.

3) Test an API with an API client

One way to test an API is Postman which is an API Client designed to give a visual interface to API retrieved data.

With Postman you can access the contents of the API. This content often requires authentication to be able to do so with the use of login credentials and authentication tokens, which can be input into Postman.

💡
Note the API here has had Get, Post, Store, Patch and Delete calls here created and set up.
💡
Patch tripped me up somewhat, it turned out x-www-for-urlencoded was the input method that should have been selected when originally selected was just form - which worked fine for the store.
  1. API Controllers and Folder Structure

  2. When creating an API controller that reflects it web counterpart a key difference is that the API version does not deal with methods which return views as the API is not interacted with on the client side.

  3. Notably, the create and edit are missing as these would have the purpose of loading a client-side interface that a user would interact with over the browser.

  4. An API, however, does not receive data from an inputted form on the client side. It is passed the data, most likely via JSON.

  5. API Requests

    Validation request classes are used to check API data for errors and are called from the controller.

    There is very little difference between the Request classes called by an API controller the from the Request classes used for web Controller.

  6. API Resources

    When a record is retrieved from its database via an API, by default it will retrieve all fields in that record. This may include unwanted or sensitive data.

  7. A resources file resticts what the API code sends to the code base or API client that consumes it.

  8. API Testing with PEST

    Testing an API functionality with PEST involves several differences from testing web functionality.

    Use of JSON
    API tests that are sending and receiving data via JSON must specific the correct function names. An example is specifying JSON data when testing post requests.

    postJson(route('api.albums.store'), $data) ->assertCreated();

    Becomes

    post(route('albums.store'), [ 'title' => $this->faker->title ])

    Another example is when checking errors in the JSON data.

    $this->post(route('albums.store'), [ // )
    ->assertSessionHasErrors([ // ]);

    Becomes

    postJson(route('api.albums.store'), [])->assertJsonValidationErrors([ // ]);

    See an example Api test below:

  9.  test ('can store album', function () {
    
         $title = $this->faker->title;
    
         $data = [
             'title' => $title,
             'description' => $this->faker->sentence,
             'cover_file_path' => UploadedFile::fake()->image('logo.png')
         ];
    
         postJson(route('api.albums.store'), $data)
              ->assertCreated();
    
         assertDatabaseHas('albums', ['title' => $title]);
     });
    

    Tested Verbs

    When testing an API controller, it's important to note that there are some differences in the verbs used compared to testing a non-API controller. This is because the API controller doesn't have methods for creating and editing data since these actions are usually performed through user input on the client side. This difference is reflected in the naming conventions used for testing API controllers versus non-API controllers.

    See folder structure below:

  10. Views are not tested

    Since the controller of an API does not contain methods that are responsible for returning view there is no need to assert if views load.