Laravel API Series: Validation and Table Relationships
Tags: laravel, webdev, beginners, tutorial
Published: 2022-04-22 00:31:12

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a1mbpwhcmm0505re3fig.png)
- 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:
```php
        $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:
```php
    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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xhvvxf22viibaph5zii4.png)
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:
```php
    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](https://laravel.com/docs/9.x/validation). 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:
```php
    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:
```php
    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:
```php
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/von93ulnupwin4hdani0.png)
 

- 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:
```php
    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:
```php
    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:
```php
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2vy6o95bzz8lyd66go53.png) 
 
- 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.

Please use the comment section for suggestions and feedback, I would really appreciate that. I hope you enjoyed the article!