• Labs icon Lab
  • Core Tech
Labs

Guided: Developing a RESTful API with Authentication in Laravel

In this Guided Code Lab, you will learn how to utilize Laravel's built-in features to build your own RESTful API for managing resources. You will implement all of the CRUD operations with the resource controller and connect them to the API endpoints. Finally, you will also learn how to use Laravel Sanctum package to easily implement token-based authentication to restrict the usage of your API to registered users only.

Labs

Path Info

Level
Clock icon Intermediate
Duration
Clock icon 1h 14m
Published
Clock icon Mar 08, 2024

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. Challenge

    Introduction

    In this Guided Code Lab, you will learn how to create a REST API in Laravel and how to protect it with authentication. Authentication will be implemented with the Laravel Sanctum package. The API will allow the users to manage items in some kind of a storage unit.

    Each task can be validated individually by clicking on the Validate button next to it.

    If you are stuck, you can always check out the details section of the task or the solutions directory. The task will give you feedback if you don't complete it correctly. A failed task will have one or more failed tests under the "checks" section of the task. You can check out the output of these failed tests to see what went wrong.

    The starting point of the Lab is a new Laravel application named "items-api". The current directory of the build-in Terminal will be set to the items-api/ directory.

    Notice that you will have access to two Terminal windows.

    1. You can use the first Terminal to run the development server with the Artisan CLI or to run other Artisan commands. The Run button will automatically start the Artisan development server.
    2. The second Terminal can be used to test the API endpoints with the curl command. There will be an explanation of which commands you have to run as you get to each specific task.
  2. Challenge

    Creating the Item Resource

    A REST API is a set of rules and conventions for building and interacting with web services. These types of APIs are often used to manage resources and in this lab you will manage the Item resource.

    To do that, you first need to be able to store the instances of that resource in some kind of a database. To keep things simple, you can use SQLite. The database connection is already configured inside of the .env file with just one variable: DB_CONNECTION=sqlite.

    The database file is already created inside of the default directory database/database.sqlite. If you need to create it in your own projects, it's enough to just create the file with the same name, which you can do with the touch command: touch database/database.sqlite.

    After the database is configured, you need to create the Eloquent ORM model to manage the Item resource in the database. Once the migration is created, you need to specify the properties of the Item resource, which would correspond to columns in the database. You should also prepare the model for mass assignment. This will help you down the line, when you decide to create new items in the database. The migration file is now complete, but you need to migrate these changes so that the real items table can be created inside of the SQLite database.

  3. Challenge

    Implementing the Item's Controller and Routes

    The Item model is ready. Now you need to implement some business logic that will actually let the user manage items through the API endpoints.

    The best way to implement CRUD (Create, Read, Update, Delete) operations on a single resource is to use Laravel's resource controllers. A resource controller will automatically create all of the actions you need for CRUD. When working with APIs, you don't need the create and edit actions, since these are usually used for rendering HTML forms. The controller's actions are empty for now. However, even if you did add some logic already, you wouldn't be able to use it because each action needs to be connected to a specific route endpoint. This table shows which route needs to be connected to which action:

    | Verb | URI | Action | |-----------|-----------------------|---------| | GET | /items | index | | POST | /items | store | | GET | /items/{item} | show | | PUT/PATCH | /items/{item} | update | | DELETE | /items/{item} | destroy |

    Instead of specifically defining each route, you can utilize Laravel's special methods for creating resource routes, which will follow the rules of the table provided above.

    The routes have to be created inside of the app/routes/api.php file. That file is specifically designed to work with API middleware, as opposed to the web.php file, which is used for monolithic applications. All routes placed inside of the api.php file will have the /api prefix in the route path.

  4. Challenge

    Creating and Showing Items

    The controller is created and actions are connected to the appropriate resource routes. It's time to actually define the logic for each controller action.

    The store action should receive the name and stock from the POST request and use that data to create a new Item in the database. If you want, you can now start up the server by clicking on the Run button or just running php artisan serve in the first Terminal.

    After the server is running, you can use the second Terminal to try out the first action you created. To do that you can use this curl command:

    curl -X POST http://localhost:8000/api/items 
         -H "Content-Type: application/json" 
         -d '{"name": "Example Item", "stock": 10}'
    
    About the curl command You can use the `curl` command to make requests to an API. The `-X` flag defines that the request will use the `POST` HTTP method because you need to send the `name` and `stock` data to the server. It is a good practice to use `-H` to define that you are sending data as JSON.

    The -d flag provides the actual data you want to send to the server. In this case, the POST request to the /api/items route will trigger the store action in the ItemController.

    Of course, you can change the input data to whatever you want. This is not a task, but you should know how to try out your API endpoints. The successful response should return the same data you sent with the request.

    If you want to check the items table directly from the database, you can use this command to see if you new item was saved:

    sqlite3 database/database.sqlite "SELECT * FROM items;"
    

    However, you will also be able to see all of the items from the database, once you define the actions for showing the resource. The index action usually returns all of the resource instances from the database. You can test this route with this curl command:

    curl -X GET http://localhost:8000/api/items -H "Accept: application/json"
    

    Finally, you should also implement the show action. This action should retrieve just one item, based on the route parameter from the route path. The parameter contains the id of the requested item. You can test this route with the following curl command:

    curl -X GET http://localhost:8000/api/items/{id} -H "Accept: application/json"
    

    Replace the {id} with the existing item id. If you created just one item, you can replace the id parameter with id 1.

  5. Challenge

    Updating and Deleting Items

    Users can now create and see items. In the spirit of RESTful APIs, you also need to implement the rest of CRUD operations.

    Define the update action, which will be used to update the data of existing items in the database.

    Both fields from the request should use the sometimes validation rule because this will allow users to do a partial update, instead of always having to provide values for all of the fields. If you want, you can also test this endpoint with curl.

    Test the update action You can use this command to test it: ``` curl -X PUT http://localhost:8000/api/items/1 -H "Content-Type: application/json" -d '{"name": "Updated Item Name", "stock": 20}' ```

    This command will update the item with id 1, but you can change that to some other id in the route parameter. The -d flag will provide new data. You can also try to remove one of the fields because partial updates should also work.

    The PUT and PATCH are often used interchangeably, although PUT should be used for updating all of the fields, while PATCH should only do partial updates. In Laravel, you can use any of these two to access the update route.

    To finish all of the CRUD operations, you still need to allow users to delete items. And that's it! You just finished defining all of the CRUD operations for the item resource. You have a functional REST API.

    To test the destroy action, you can use this curl command:

    curl -X DELETE http://localhost:8000/api/items/{id}
    

    Of course, replace the {id} from the route parameter with the real id of the item that you want to remove.

  6. Challenge

    Registering Users

    The REST API for managing items is now finished. The next step is to implement authentication to protect the routes, so that only registered users can actually use the API.

    Fortunately, Laravel has the Sanctum package for this very purpose. Before the version 10 of the Laravel framework, you had to install Sanctum yourself with the composer package manager and publish its configuration files to your project. However, since version 10, Sanctum is included by default in every new project you create.

    You can check out the composer.json file to see that the package is already an installed dependency. Also, the sanctum.php configuration file is present inside of the config directory, which means that Sanctum is already installed and configured.

    To utilize it, you first need to create some kind of an authentication controller. The /register route should allow guests to create an account for accessing your API. Registration will allow guests to become application users. Of course, you need to store the user information inside of the database.

    Fortunately, you can see that every new Laravel project already has few existing migrations. There is a migration for creating the users table and another for storing access tokens. Both of these are required by the Sanctum package. When you ran the migrations with the php artisan migrate command, Artisan also created all of these additional tables in the database.

    So you can use the existing User model to create new users. If you implemented everything correctly, you should be able to create new users with the curl command:

    curl -X POST http://localhost:8000/api/register 
         -H "Content-Type: application/json" 
         -d '{"name": "User1", "email": "user@example.com", "password": "pass", "password_confirmation": "pass"}'
    

    Users also need to provide the password confirmation field because of the confirmed validation rule on the password field.

    If you want to check the database table for users directly, you can use:

    sqlite3 database/database.sqlite "SELECT * FROM users;"
    
  7. Challenge

    Implementing Login Functionality

    Guests are now able to create user accounts for your application. You need to provide them with the /login route which they can use to authenticate. If they provide the correct credentials, Sanctum should send them an access token with the response. The default User model already has the hasApiTokens trait included in the model's class. This is all you need to utilize Sanctum's methods on User instances.

    The login action should validate the email and password from the request data. If both of these fields are valid, you can find the user in the database and return their access token. This implementation of the login action will work, but only if the user definitely exists in the database. Also you are not checking if the password matches the user's password. These things need to be fixed. You can try to login with the existing account you created in the registration step. Of course, if you didn't create the account yet, go and create it with the /register route. Once you do that you can use curl to provide the credentials to the /login route:

    curl -X POST http://localhost:8000/api/login -H "Content-Type: application/json" 
         -d '{"email": "user@example.com", "password": "pass"}'
    

    If you provide the correct credentials, you will get an access token back from the server.

  8. Challenge

    Protecting the Routes with Authentication

    Only registered users should be able to manage items in your application. To protect the API resources, you can use the Sanctum's middleware in the api.php file.

    This is how you could apply the middleware to a single route or a collection of resource routes:

    Route::middleware('auth:sanctum')->apiResource('items', ItemController::class);
    

    However, in most applications with authentication, you will put more than one route or resource under the protection of the authentication middleware. You can check if the routes are protected by using this command:

    curl -X GET http://localhost:8000/api/items -H "Accept: application/json"
    

    This command will simply try to access the route that shows all of the items. However, the response you should get is the Unauthenticated message.

    To access this route, you also need to provide the access token inside of the Authorization header. The value of this header is Bearer followed by the access token.

    curl -X GET http://127.0.0.1:8000/api/items -H "Accept: application/json" 
         -H "Authorization: Bearer ACCESS_TOKEN"
    

    Of course, you need to replace the ACCESS_TOKEN with the actual token you get back once you login. Try to login again and provide the access token in this header.

    Finally, it's also a good practice to create the logout action which will delete the existing access token. If you want to test this route, you can use this command with the existing access token:

    curl -X POST http://localhost:8000/api/logout -H "Accept: application/json" 
         -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
    

    And that's it! Congratulations, you just created a RESTful API with authentication in Laravel!

    What's next? What more can you do to improve upon this basic API?

    Here are some suggestions:

    • Implement pagination for the index action, your server will be blocked with requests if it has to return all of the items from the database.
    • Use TLS certificate to set up the secure HTTPS connection. This is a must for all modern web applications with authentication, otherwise you risk vulnerabilities like the man-in-the-middle attack.
    • To setup specific rules on what each user can do, you can simply add Sanctum abilities to the middleware.
    • Implement rate limiting to protect your API from abuse. Laravel has built-in features for that.
    • Version your API. The easiest way to do that is to place the version number directly inside of the route path.
    • Use tools like Swagger to create a documentation for your API endpoints.
    • Use tools like Laravel Telescope for debugging and monitoring your API's performance in production.
    • Be mindful of Eloquent's performance. Use eager loading to reduce the number of queries to the database.
    • Implement caching to store responses and reduce database queries for frequently accessed data.

Mateo is currently a full stack web developer working for a company that has clients from Europe and North America. His niche in programming was mostly web oriented, while freelancing, working on small startups and companies that require his services. Go(lang), Elixir, Ruby and C are his favorite languages and also the ones he’s mostly working with other then PHP in day to day work. He has a big passion for learning and teaching what he knows the best. His big interests recently have been the fields of DevOps, Linux, functional programming and machine learning.

What's a lab?

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Provided environment for hands-on practice

We will provide the credentials and environment necessary for you to practice right within your browser.

Guided walkthrough

Follow along with the author’s guided walkthrough and build something new in your provided environment!

Did you know?

On average, you retain 75% more of your learning if you get time for practice.