Generalizing API Response & Error Handling — Laravel

Image for post
Image for post
Photo by Negative Space from Pexels

ome people say that if you want to develop an API, then you have to look at your API consumer’s perspective. It means that, all the responses (whether they are errors or not) must have a consistent and standardized JSON structure/response. So in this article, I will show you how to generalize API responses that can be used in a Laravel project and how to handle errors.

Content Overview

  • Migration
  • ApiResponser
  • Parent ApiController
  • Extends to ApiController
  • Api Routing
  • Error Handler

Before we start, I will create a general JSON structure for this entire project. Of course, you can create your own API response structure. This structure will be used in every response we return to the API consumer.

{
"status" : "Success",
"message" : null,
"data" : null
}

We have the structure now, let’s implement it!

Migration

Setup the Laravel project first using composer

composer create-project --prefer-dist laravel/laravel generalizing-response

Then, we need to migrate the database. In this article, let’s don’t talk about making complicated tables. We can use the migration template for Users that Laravel has when we create a new project. You can find it in the database->migrations->create_user_table.php. So, let’s run the migration

php artisan migrate

Don’t forget to set your database in an .env file of your project. If your migration is successful, then you can see new tables appear in your database.

ApiResponser

First thing first, let’s create an API response structure. We will create a new file in app/Traits/ApiResponser.php which will give you a general model of the JSON response. You can modify it as you wish, but in this case we stick into our standard response as explained above.

app/Traits/ApiResponser.php

Parent API Controller

So far, we have created the standard response file. Then, we must always use this response file every time we return something to the API consumer. Imagine that we have 10 or more controllers when working with large projects, it’s very ineffective when we import this ApiResponser.php in every controllers that we have.

So what’s the solution? The solution is, we create a parent class named Api Controller and every controller that we have must extend from that parent. Then, in the Api Controller we can import the Api response class. So, every function that the Api Response & Api Controller has can be called on every controller that extends from it. Let’s implement it.

Create a new controller with php artisan:

php artisan make:controller ApiController

Then inside app/Controllers/ApiController.php

app/Controllers/ApiController.php

As you can see there, in the ApiController we import the ApiResponse that we have created before.

User Controller

Ok next, we’ll configure the UserController to make this thing works.

php artisan make:controller User/UserController -r

Then inside your app/Controllers/User/UserController.php:

app/Controllers/User/UserController.php

In the UserController, we always use the method from the ApiResponser class. So, we don’t need to manually type return->response again and again. If you want to modify the response structure, you can do that in the ApiResponser class. You don’t need to modify it in every controller.

For set up the user login, let’s create a new controller:

php artisan make:controller User/UserLoginController -r

Inside User/UserLoginController.php:

app/Controllers/User/UserLoginController.php

Api Routing

Last thing to do in this part 1 project is adding some routes. Let modify the routes/api.php

routes/api.php

What’s next?

If you try it now, it should work! But the problem is, like I mentioned above, as an API consumer, we want to know everything that happens in the system, including when an error occurs. Until this step, I haven’t talked anything about the error handling. So, if you try to make a mistake, this is what happens:

Image for post
Image for post

We got the html based error response. We don’t need that, because the API consumer won’t process these type of data because they always expect to receive a JSON response.

Error Handler

It is time for us to handle these types of errors. Let’s open the app/Exceptions/Handler.php

app/Exceptions/Handler.php

As you can see there, we add so many exceptions inside the handleException() function. By default, the handleException() function doesn’t exist, so you must modify the render() function to use the handleException(). You can add as many exceptions as you want inside this function.

We might want to see html based error responses for the sake of debugging but, we don’t want to do it in a production environment. So, we use config(‘app.debug’) in the handleException() to provide the different responses for development and production when handling the unexpected errors. The best practice is, you can have html based error responses in the development, but not in the production.

It’s done! I have prepared the github and postman collection below. I hope this article will be a useful reference for you.

If you want the complete project:
Github:
https://github.com/Cerwyn/laravel-generalizing-response

Postman API Collection:
https://www.getpostman.com/collections/7a71f32c828dab979455

References:
https://www.udemy.com/course/restful-api-with-laravel-php-homestead-passport-hateoas/

PHP/Backend Engineer at Undercurrent Capital Pte Ltd — Data Science Enthusiast

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store