Ultimate guide to RESTFul API Versioning in PHP Laravel: 2 solutions

Ultimate guide to RESTFul API Versioning in PHP Laravel: 2 solutions

Last Updated on Feb 15, 2023

Are you going to change the behavior of your API?
Are you going to change the structure and format of requests and responses of your API?

If your answer to both questions is “Yes” then API versioning is exactly what you need.

When should/shouldn’t the API be versioned?

The short answer:
When there are some major changes in the structure and/or behavior of the API that affects the request and response, a new version will be introduced.

These changes can be changing the XML response to JSON, adding a new required parameter to the request, changing the authentication, etc.

However, if the change is not affecting the current request and response, there is no need to add a new version to the API.

Let me give you an example:

Our current API for getting a list of users looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<users>
  <user>
    <name>john doe</name>
    <age>50</age>
    <email>john.doe@example.com</email>
  </user>
  <user>
    <name>mary jane</name>
    <age>45</age>
    <email>mary.jane@example.com</email>
  </user>
</users>

Scenario 1

We want to change it to JSON response. Something like this:

{
    "users":
    [
        {
            "name": "john doe",
            "age": "50",
            "email": "john.doe@example.com"
        },
        {
            "name": "mary jane",
            "age": "45",
            "email": "mary.jane@example.com"
        }
    ]
}

It will break the applications that are dependent on our API. So we have to add a new version to API.

Scenario 2

Sometimes the change looks simple and minor, but still it will affect the users who are using our API. We want to change the age from being a node to an attribute. And we change our response to something like this:

<?xml version="1.0" encoding="UTF-8"?>
<users>
  <user>
    <name age="50">john doe</name>
    <email>john.doe@example.com</email>
  </user>
  <user>
    <name age="45">mary jane</name>
    <email>mary.jane@example.com</email>
  </user>
</users>

It’s a minor change, but it definitely affects the users who are using our API. So we have to add a new version.

The next two scenarios, are examples of when we should not version the API.

Scenario 3

We want to add country to our response. So the final response looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<users>
  <user>
    <name>john doe</name>
    <age>50</age>
    <email>john.doe@example.com</email>
    <country>germany</country>
  </user>
  <user>
    <name>mary jane</name>
    <age>45</age>
    <email>mary.jane@example.com</email>
    <country>france</country>
  </user>
</users>

Here we have not changed any old structure or behavior, and we have added a new one. There is no need to add a new version to the API, but instead we send a notification email and a new documentation to all of our users saying, “we have added a new feature. Now you can get the country of the users as well”. That’s it.

Scenario 4

This one is exactly like scenario 1. But, we do not change the response to JSON, we add it as a feature, and we set the default response to be XML. Now, user can send “accept: application/json” in the header and get the JSON response. Otherwise, we will send an XML response. Here we do not need to add a new version as well.

Again, we send a notification email and a new documentation to all of our users saying, “we have added a new feature. Now you can get JSON response. For details, please refer to the documentation”.

How to version a RESTFul API?

According to rest API standards for versioning, there are 2 main ways:

URI

If you introduce the version to the URI in any manner, it falls in this category. For example:

http://api.example.com/v1
http://apiv1.example.com
http://example.com/api/v1
http://example.com/apiv1/

if you introduce the version to the header, whether its a custom header like “Accept-version” or the standard “Accept” header, it falls in this category. for example:

Accept-version: v1
Accept: application/vnd.example.v1+json
Accept: application/vnd.example+json;version=1.0

Now let’s get to coding.

RESTful API Versioning in Laravel

Setup

For the examples below, I’m using Laravel 8.
When I talk about routes and changing them, I am changing the routes in api.php, not web.php.
For easier demonstration, I write the codes of each route in the closure, unless a controller is necessary. You can refactor those closures to separate controllers.

Solution 1: Add versioning to URI in Laravel

A simple and fast way is to simply write the version before each route.

Route::get('/v1/users', function (Request $request) {
    // version 1
});
 
Route::get('/v2/users', function (Request $request) {
    // version 2
});

If you have many routes, it would be hard to add a name one by one. So you could use group and prefix functionality of Laravel.

Route::prefix('v1')->group(function () {
    Route::get('/users', function () {
        // Matches The "/v1/users"
    });
});
 
Route::prefix('v2')->group(function () {
    Route::get('/users', function () {
        // Matches The "/v2/users"
    });
});

Solution 2: Add versioning to header in Laravel

in Laravel, you can get the accept header like this:

$request->header('accept')

The code above will return something like this:

"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"

You should check the version inside the header. for example:

Route::get('/user', function (Request $request) {
    if((strpos($request->header('accept'), 'v1') !== false)){
        // version 1
    }else if((strpos($request->header('accept'), 'v2') !== false)){
        // version 2
    }
});

If you have decided to use a custom header rather than the “accept” header, make sure to check if it exists first:

Route::get('/user', function (Request $request) {
    if ($request->hasHeader('custom-header-name')) {
        if((strpos($request->header('custom-header-name'), 'v1') !== false)){
            // version 1
        }else if((strpos($request->header('custom-header-name'), 'v2') !== false)){
            // version 2
        }
    }
});

Final Words

The goal of this post was to help you version your API in Laravel. That’s why I tried to use the basic structure and format that can be used in Laravel. However, you can refactor this simple solutions to any structure and design patterns that you like.
– You can separate the routes of each version to a new file and then include them in the main file.
– You can separate the functionality of each controller to different services.
– You can separate the functionality of each version to static methods.
– You can add a middleware to check for the header.
And many other possible ways, thanks to Laravel’s amazing power and flexibility.

Conclusion

Now you are able to version a restful API in Laravel. You can add it to your list of skills.

I recommend you create a new Laravel project and try to apply everything we learned. It would be a good practice. Or if you already have a project, you can decide if it needs versioning. In case it does, you can start working on it right away.

If you have any suggestions, questions, or opinion, please leave a comment below. I’m looking forward to hearing from you!

Key Takeaways

  • Decide if your API needs versioning
  • Decide if you want to version your API with Headers or with URI
  • Apply your solution to your Laravel Application

 

https://youtu.be/cFlYQ_nxeJA

 

Category: programming

Tags: #php #laravel #RESTFul #tips and tricks

Join the Newsletter

Subscribe to get my latest content by email.

I won't send you spam. Unsubscribe at any time.

Related Posts

Courses