Laravel API Series: Validation and Table Relationships

Laravel API Series: Validation and Table Relationships

What you'll learn

In this part of the series, you'll learn the following:

  • What is validation
  • How to implement validation in Laravel
  • Implement table relationships

What is Validation?

Validation, in the scope of this project, is the process of making sure the input going into the API is the required and acceptable one, and the output the API is sending back to the user is the correct and useful one.

Validation in Laravel

Laravel makes validation easy to work with by providing developers with a validate method that is available on all incoming HTTP requests. That said, to show you how validation works in Laravel, I'll set up validation for the store functions of both the PostController and AuthorController.

First, I'll check what I get when I send nothing with the POST request in Postman: default validation error

  • The purple box is the type of request I made, which is a POST request.
  • The yellow box is the URL I sent the request to; localhost:8000/api/posts.
  • The red box is the data I sent with the request, which is nothing.
  • The green box is the result of the request, which is the default validation error, telling me Field 'title' doesn't have a default value, which means I need to provide the title of the post I want to create, not because it's required though, but because it is listed in the $fillable array inside the Post model and because I didn't add a default value to it inside the migrations file. But that error doesn't look good, and most times, you only want a simple error message like "title is required" or something similar that you can send back to the client, so they know what the issue is and how to move forward.

So to send a better error message, go to your PostController's store function and add the following code:

        $request->validate([
            'title' => 'required',
            'author_id' => 'required',
            'body' => 'required'
        ]);

The above code makes use of the validate method on the $request object, and adds the required fields as an array, in my case the title, author_id, and body fields are required to successfully create a post. So your store function now looks like so:

    public function store(Request $request)
    {
        $request->validate([
            'title' => 'required',
            'author_id' => 'required',
            'body' => 'required'
        ]);
        return Post::create($request->all());
    }

Now send the same request I sent at the beginning of the section to see the new and readable error message: readable error message The description of the above image is the same as the previous one, except for the green box, which in this case, shows nicely formatted error messages.

Note: You need to set the Accept header in your HTTP client to application/json for all your requests, especially when you set validation messages like you did above or the validate method might not work.

Lets do the same for the AuthorController's store function, like so:

    public function store(Request $request)
    {
        $request->validate([
            'author_email' => 'required|unique',
            'author_name' => 'required',
        ]);
        return Author::create($request->all());
    }

Notice the required|unique?, this allows you to avoid saving the same Author to the database multiple times by making sure all the requests to create a new Author contain an email that has not been previously registered.

This is all for validation in our application, you can read more on validation in Laravel here. Next, we'll move on to table relationships continuation.

Table relationships (Contd.)

In the first part of the series, you learned that to use the relationship feature in Laravel, you need to have two or more tables in the database.

In this section, I'm going to show you how to connect the Author table to the Post in a way that a single Author can have multiple posts. To do that, go to your Author model file, and add the following code inside the class, like so:

    public function posts()
    {
        return $this->hasMany(Post::class);
    }

The above code makes use of the hasMany method to create an eloquent relationship that uses the author_id as a foreign key to connect the tables.

Note: You need to have the 'author_id' in your post table for the above to work, else you'll need to put the name of the field you use to uniquely identify each author as a foreign key next to the class so: $this->hasMany(Post::class, 'foreign_key'). The above code works without the foreign key because Laravel assumes that you use the parent model name with _id suffix as your foreign key, which is correct in my case: author_id.

Next, you need to create a controller function that returns the list of posts for a particular author, you do that inside the AuthorController like so:

    public function get_posts($id)
    {
        $posts = Author::find($id)->posts;
        return $posts;
    }

The above code makes use of the find method with the id as a parameter on the Author model, and then it returns all the posts of that author.

After that, connect the above get_posts function to a route by adding the following code to your api.php file like so:

Route::get('/author/posts/{id}', [AuthorController::class, 'get_posts']);

The above route connects the get_posts function to any GET request that goes to the http://localhost:8000/api/authors/posts/2 route, which will then return all the posts for the author with the id of 2 like so:

author posts

  • The purple box is the type of request I made, which is a GET request.
  • The yellow box is the URL I sent the request to; http://localhost:8000/api/author/posts/2.
  • The green box is the result, which is all the posts that belong to the author.

Connecting a post to a single author

We've looked at how to get posts from a single author. Now let's look at how to get the author of a post. To do this, add the following code to your Post model:

    public function Author()
    {
        return $this->belongsTo(Author::class);
    }

The above code connects the Post table to the Author table inversely. After that, add the following code to the PostController like so:

    public function get_author($id)
    {
        $author = Post::find($id)->author;
        return $author;
    }

The above code makes use of the find method with the id as a parameter on the Post model, and then it returns the author of that post.

Next, connect the above get_author function to a route by adding the following code to your api.php file like so:

Route::get('/posts/author/{id}', [PostController::class, 'get_author']);

The above route connects the get_author function to any GET request that goes to the http://localhost:8000/api/post/author/6 route, which will then return the author of the post with the id of 6 like so:

post author result

  • The purple box is the type of request I made, which is a GET request.
  • The yellow box is the URL I sent the request to; http://localhost:8000/api/post/author/6.
  • The green box is the result, which is the author of the post.

Recap

In this part of the series, you learned about and how to do the following:

  • Check if the validation works on an endpoint
  • Validate the request object using the validate method
  • Create a one-to-many relationship between Author and Post using the hasMany method
  • Create the inverse of the one-to-many relationship between Author and Post using the belongsTo method
  • Connect the newly created functionalities to routes

In the next part, you'll learn how to set up Laravel Sanctum for the API authentication, and create the Sign-Up, Sign In, and Logout functionalities.