Some 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.
- 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!
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.
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.
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
As you can see there, in the ApiController we import the ApiResponse that we have created before.
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:
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
Last thing to do in this part 1 project is adding some routes. Let modify the routes/api.php
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:
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.
It is time for us to handle these types of errors. Let’s open the 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:
Postman API Collection: