JSON APIs with Laravel: Part 4 - Controller Methods and Data Validation cover image

JSON APIs with Laravel: Part 4 - Controller Methods and Data Validation

Oliver Sarfas • August 19, 2019

programming laravel

This a part of my "JSON APIs with Laravel" series. If you've missed any of the previous episodes you can find them at the bottom of this article


Recap

We've got some Models, populated by factories, which are triggered by seeders. The Models have data which is exposed in our Controller methods and available on our endpoints wired up by our Routing.

TL;DR We've got stuff, showing in some places.

So far so good.

Now let's handle the EAD in our BREAD, and get some more endpoints populated.


Edit, Add, Delete

First up, we'll do Delete. Sounds weird to start at the end, but it's by far the easiest to implement.

DELETE Endpoint

Go to the destroy method in ContactController and you'll find the following;

public function destroy( Contact $contact )
{

}

We need to add the business logic to this. Put simply, all we want to do is delete the contact given, so let's add that now;

public function destroy( Contact $contact )
{
    $contact->delete();
}

Now what do we return to the user? All the contacts? An empty response? 404 as the resource no longer exists?

Personally, I'll return an empty response, with a HTTP 200 code. However you may find that returning your index() function is preferred in your application - very helpful for SPAs.

We're going to return a HTTP 200 empty response here.

public function destroy( Contact $contact )
{
    $contact->delete();
    return response()->json([]);
}

ADD Endpoint

The ADD endpoint can be found in the store method of the controller;

public function store(Request $request)
{

}

Right now, all it's doing is taking the request, and doing nothing with it. What we want to have (in terms of flow) is the following;

A couple of things to consider however are;

Idempotency

What do we do if someone submits the same details twice, in the space of a minute? Or the same details for a contact we already have?

Create a new one? Return the existing? Well, that's entirely up to you.

By the "rules" of REST, your POST endpoint for creating a resource should be idempotent, however you'll rarely find that this is the case in the wild.

Personally, I try to stick to this wherever possible, but sometimes the business doesn't want this, so you have to "go rogue" and build without.

Authentication

Currently our API is open, as intended. If we wanted to restrict users to certain actions, or even lock down endpoints to locations/ ip addresses, etc. we'd need some form of authentication.

In API terms, this is usually done with tokens, or username & passwords. We'll pick this up in a future episode, however for now we'll leave it open

Actual Code now..!

Ok, so our store method needs to validate our request before handling the data. Luckily Laravel makes this really easy and has some commands that will help. run the php artisan make:request CreateContactRequest in your console, and you'll get the file app\Http\Requests\CreateContactRequest.php file.

The full documentation of this Request concept can be found on the laravel website

<?php

namespace Http\Requests;

class CreateContactRequest extends FormRequest
{
    public function authorize()
    {
        return false;
    }    

    public function rules()
    {
        return [

        ];
    }
}

We want this request to be authorised, and have some rules, let's populate those;

<?php

namespace Http\Requests;

class CreateContactRequest extends FormRequest
{
    public function authorize()
    {
        return true; // public endpoint, allow all
    }    

    public function rules()
    {
        return [
            'name' => 'required|max:100', // Your name can be up to 100 characters in length
            'email' => 'required|email|unique:contacts,email', // Email must be valid and unique to the database
            'contact_number' => 'required|string', // Contact number must be supplied, and a string
            'address' => 'required|string', // Address must be  supplied, and a string
        ];
    }
}

So we've got a request, how do we use it? Well, its as simple as swapping out the class in the method!

<?php

public function store ( Request $request)
{ 

}

# Becomes

public function store ( CreateContactRequest $request )
{

}

Don't forget to add use Http\Requests\CreateContactRequest; to the top of the Controller file to ensure that the class is autoloaded from the correct namespace.

Let's flesh out the functionality now.

We're going to take our validated data, and create a new Contact - given that one doesn't already exist.

<?php

public function store( CreateContactRequest $request )
{
    $contact = Contact::firstOrCreate( $request->validated ()); // create or retrieve record
    return response()->json($contact); // return record
}

That's it. 2 lines. It's so elegant and simple to do. Easy to modify, read, and maintain.

EDIT Endpoint

Edit runs very much the same as Add, so I won't go into as much detail - in fear of repeating myself needlessly.

The edit endpoing is update in the controller, which can be found starting with;

<?php

public function update(Request $request, Contact $contact)
{

}

For this, create a new request (so that you can validate the data, call it UpdateContactRequest), type hint that against the method, and then just update the resource as necessary.

You'll end out with the following;

<?php

public function update(UpdateContactRequest $request, Contact $contact)
{
    $contact->update($request->validated);
    return response()->json($contact);
}

Next Up

Next time, we'll look at Authentication, and ensuring that only certain users / keys can do certain actions. There are some great packages out there for this, and we'll be exploring those.


Previous Episodes

Episode 1

Episode 2

Episode 3