This is part 3 of the Laravel 5 & Dingo API series, in which we’re building an API to receive orders from 3rd parties and ship them to recipients. Last time we covered setting up the database, creating migrations and setting up models. This time we’re going to focus on Laravel’s controllers and how we get them working with Dingo API in order to create, read and update data stored in our database.
Controllers
I’m going to start with a variant controller as it has more information that can be returned with a get request and we wouldn’t allow 3rd parties accessing the API to create any variants. This makes it much simpler to build.
With Dingo API, we should specify a base controller to pull all of the helper functions into our individual controllers using inheritance. To do this run:
php artisan make:controller api\\BaseController
Open the BaseController.php file in Atom and add edit it to look like the following:
<?php namespace App\Http\Controllers\api; use Dingo\Api\Routing\Helpers; use Illuminate\Routing\Controller; class BaseController extends Controller { use Helpers; }
This is simply inheriting the Controller class, then using the Helpers and creating a new BaseClass to extend from in our API.
We’re going to create a VariantsController, and to keep things organised lets also make it in a subfolder of the application. From the command line run:
php artisan make:controller api\\VariantsController --resource
Now open the controller in Atom and after the use statements at the top of the file add one for the Variants model:
use App\Variants;
You’ll notice because we specified the “–resource” flag at the end of our command line action, the controller has been populated with a skeleton framework of RESTful functions. In the “index” function lets add some code to return all of our variants from the database:
public function index() { return $this->response->array(Variants::all()); }
Before we can test this, lets update our routes.php file to use the new controller:
$api = app('Dingo\Api\Routing\Router'); $api->version('v1', function ($api) { $api->get('/', function() { return ['test' => true]; }); $api->get('/variants', 'App\Http\Controllers\api\VariantsController@index'); });
So, now if you navigate to /api/variants (http://localhost:8000/api/variants/) you should get Dingo API returning all variants in the database. (note you may need to run php artisan serve from the command line first, and if you didn’t seed the database you’ll get an empty response [] ). If you didn’t seed your database, why not add some records and see what responses you get, for example I’ve added a variant and the response is now:
{ "variants": [ { "id": 1, "size": "small", "brand": "fashion", "type": "hoodie", "colour": "black", "design": "blank", "created_at": "-0001-11-30 00:00:00", "updated_at": "-0001-11-30 00:00:00" } ] }
At this point, we know our routing is working, and that we’re able to connect to and query a database as well as returning a response to the user. Lets create the Orders and Items controllers:
php artisan make:controller api\\ItemsController --resource # Controller created successfully. php artisan make:controller api\\OrdersController --resource # Controller created successfully.
Lets fill in the functionality to get all items first. Open up the ItemsController in Atom and add the use statement, update it to use the dingo base controller as well as the index function code:
use App\Items; class ItemsController extends BaseController
public function index() { return $this->response->array(Items::all()); }
While we’re in the items controller, lets add the ability to find a single item in the show method
public function show($id) { return $this->response->array(Items::find($id)); }
As part of the URL, we will pass the item ID, which allows us to do a database search for that item and return the response. If no item is found it’ll return an empty array.
We can save items like so:
public function store(Request $request) { $item = new Items; $item->item_ref = $request->input('item_ref'); $item->quantity = $request->input('quantity'); $item->variant_id = $request->input('variant_id'); $item->save(); }
We can also allow updates for an item:
public function update(Request $request, $id) { $item = Items::find($id); $item->item_ref = $request->input('item_ref'); $item->quantity = $request->input('quantity'); $item->variant_id = $request->input('variant_id'); $item->save() }
And finally delete an item:
public function destroy($id) { $item = Items::find($id); if ($item->delete()) { return $this->response->array(['id' => $id, 'status' => 'deleted']); } }
in the routes.php file, add the methods that we want for the items controller
// Items $api->get('/items', 'App\Http\Controllers\api\ItemsController@index'); $api->post('/items', 'App\Http\Controllers\api\ItemsController@store'); $api->get('/items/{id}', 'App\Http\Controllers\api\ItemsController@show'); $api->patch('/items/{id}', 'App\Http\Controllers\api\ItemsController@update'); $api->destroy('/items/{id}', 'App\Http\Controllers\api\ItemsController@destroy');
Now you should be able to use Postman to create items:
POST | http://localhost:8000/api/items/ { "item_ref": "Test1", "quantity": 5, "variant_id": 1 }
Select items
GET | http://localhost:8000/api/items/ { "items": [ { "id": 1, "item_ref": "Test1", "quantity": "100", "variant_id": "1", "created_at": "2016-03-09 16:00:52", "updated_at": "2016-03-09 16:07:34" } ]
update items
PATCH | http://localhost:8000/api/items/1 { "item_ref": "Test1", "quantity": 100, "variant_id": 1 }
and delete items:
DELETE | http://localhost:8000/api/items/2 { "id": "2", "status": "deleted" }
Have a play with the items controller and Postman to make sure your routes and actions are working as expected before moving on. These implementations are not perfect, but it’s enough to get started. Later we’ll see how we can perform validation and even use transformers to alter requests.
The Orders Controller
The orders controller is going to be a duplicate of the items controller to begin with. All of the functionality we added into it we will add into this.
use App\Orders; class OrdersController extends BaseController
Adding the index method to list all orders
public function index() { return $this->response->array(Orders::all()); }
Adding the store method
public function store(Request $request) { $order = new Orders; $order->order_ref = $request->input('order_ref'); $order->recipient_id = $request->input('recipient_id'); $order->shipping_method = $request->input('shipping_method'); if ( $order->save() ) { return $this->response->created(); } else { return $this->response->errorBadRequest(); } }
Adding the show method
public function show($id) { return $this->response->array(Orders::find($id)); }
The update method
public function update(Request $request, $id) { $order = Orders::find($id); $order->order_ref = $request->input('order_ref'); $order->recipient_id = $request->input('recipient_id'); $order->shipping_method = $request->input('shipping_method'); $order->save(); }
and the destroy method
public function destroy($id) { $order = Orders::find($id); if ($order->delete()) { return $this->response->array(['id' => $id, 'status' => 'deleted']); } }
Finally adding the routes to routes.php
// Orders $api->get('/orders', 'App\Http\Controllers\api\OrdersController@index'); $api->post('/orders', 'App\Http\Controllers\api\OrdersController@store'); $api->get('/orders/{id}', 'App\Http\Controllers\api\OrdersController@show'); $api->patch('/orders/{id}', 'App\Http\Controllers\api\OrdersController@update'); $api->delete('/orders/{id}', 'App\Http\Controllers\api\OrdersController@destroy'
Now is a good time to commit what we’ve done in git, before moving onto refactoring it.
git add -A git commit -m "created items, orders and variants controllers with basic functionality"