How to create a Rest API with Laravel
Tags: laravel, php, rest, api
Published: 2020-11-27 12:09:39

---
title: How to create a Rest API with Laravel
published: true
date: 2020-05-16 18:02:27 UTC
tags: laravel, php, rest, api
canonical_url: https://dberri.com/how-to-create-a-rest-api-with-laravel
---

Laravel makes it quick to get up and running with Rest APIs that you can use to feed data to mobile apps, javascript applications or other applications. In this post, I'll show you how easy it is to do it.

To make it simple, let's create an API that only delivers content about books and their authors. We're not going to add "create" and "update" functionality for now.

## Setup

We can start by creating a new Laravel application. In your terminal execute the command: `laravel new books-api`. If you don't have Laravel installed globally, you can use Composer:

```sh
composer create-project --prefer-dist laravel/laravel books-api
```

> Keep in mind that by the time of this article, I'm using Laravel version 7.10.3

That will create a new folder `books-api`, you can go inside and edit the `.env` file. We need to setup the database access for the application:

```sh
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=<YOUR-DB-NAME>
DB_USERNAME=<YOUR-DB-USER>
DB_PASSWORD=<YOUR-DB-USER-PASSWORD>
```

To make sure it connects correctly, you can run `php artisan migrate`. The application already ships with database migrations for the User model. If no errors popped up, you're good to go.

## Models, Migrations and Controllers

We will need at least a model for books and one for authors, so let's create them using Artisan's command: `php artisan make:model Author -mcr`.

This command should create three files:

- `app/Author.php` : That's our model
- `app/Http/Controllers/AuthorController.php` : A resource controller (created with the help of the `cr` flag)
- and `database/migrations/XXXX_create_authors_table.php`: That's the database migration created with the help of the `m` flag in the command.

Let's start with the migration. Go to the newly created file and add the following code:

```php
public function up()
{
    Schema::create('authors', function (Blueprint $table) {
        $table->id();
        $table->string('name'); // we add this line here
        $table->timestamps();
    });
}
```

Whatever fields you add here will be added to the authors table in the database. To learn what are the available methods, check out [Laravel's documentaton](https://laravel.com/docs/7.x/migrations#creating-columns).

Now let's do the same for books: `php artisan make:model Book -mcr`.

Then go to `database/migrations/XXXXX_create_books_table.php` and add the following fields inside the `up` function:

```php
public function up()
{
    Schema::create('books', function (Blueprint $table) {
        $table->id();
        $table->foreignId('author_id');
        $table->string('title');
        $table->decimal('price', 6, 2)->nullable();
        $table->timestamps();

        $table->foreign('author_id')
            ->references('id')
            ->on('authors')
            ->onDelete('cascade');
    });
}
```

Here we are also adding a reference to the author who wrote the book using a foreign key. After you add any other fields you want, you run the migrations with: `php artisan migrate`. If you got no errors in the console, good job! Now let's keep going.

We also need to create a relationship between authors and books in the models:

app/Author:

```php
class Author extends Model
{
    public function books()
    {
        return $this->hasMany('App\Book');
    }
}
```

app/Book:

```php
class Book extends Model
{
    public function author()
    {
        return $this->belongsTo('App\Author');
    }
}
```

With these, we can call the relationships as properties from each model:

```php
$book = Book::first(); // Book instance
$book->author; // Author instance

$author = Author::first(); // Author instance
$author->books; // Collection of Books
```

If you call them using the "method" form, it will return you a QueryBuilder instance, and you can use to chain other methods, like:

```php
$author = Author::first(); // Author instance
$author->books()
	->where('published', true)
    ->get(); // Collection of Books
```

## Factories and Seeders

Now that we have the database setup, we need some data to test the API. In the real world, either you will already have the data, or maybe you can create it manually. I like to use factories and seeders, because it's less work and it's useful for automated testing. Let's create a factory for authors and for books:

```sh
php artisan make:factory AuthorFactory -m Author
Factory created successfully.

php artisan make:factory BookFactory -m Book
Factory created successfully.
```

Now if you go to the `database/factories` folder, you will see both files created.

In AuthorFactory, let's use the [faker library](https://github.com/fzaninotto/Faker) to create random Author data:

```php
$factory->define(Author::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
    ];
});
```

And we do the same for books, with the catch that it will receive the author\_id as a parameter:

```php
$factory->define(Book::class, function (Faker $faker, $author_id) {
    return [
        'author_id' => $author_id,
        'title' => $faker->sentence,
        'price' => $faker->randomFloat(2, 5, 100)
    ];
});
```

Now, we create a seeder for Authors:

```sh
php artisan make:seeder AuthorTableSeeder
Seeder created successfully.

```

In that seeder (which is in `database/seeders/AuthorTableSeeder`) we create 5 authors and 5 books for each author using the followinf code:

```php
public function run()
    {
        factory(App\Author::class, 5)->create()
            ->each(function ($author) {
                factory(App\Book::class, 5)->create([
                    'author_id' => $author->id
                ]);
            });
    }
```

It calls the factory for the Author model and for each one created, it creates 5 books using basically the same syntax. Now, to finish it up, we call this seeder in the DatabaseSeeder class:

```php
public function run()
    {
        $this->call(AuthorTableSeeder::class);
    }
```

With all migrations, factories and seeders in place, we run `php artisan migrate --seed`. You should see a list of all the migrations and seeders run.

## Routes

We need routes to access the data, so we can go to `routes/api.php` and add them there. Routes added to that file will already have a `/api` prepended to the route, so keep that in mind. I want to see a list of authors, a list of books and some details of a specific book. So, I can start by adding those three routes at the end of the file:

```php
Route::resource('authors', 'AuthorController')->only('index');
Route::resource('books', 'BookController')->only(['index', 'show']);
```

Now, since we created a resource controller in the beginning of this tutorial, we can now use the Route's `resource` static method. You pass as arguments the name of the route and a controller to map each of these seven routes:

- Index
- Create
- Store
- Show
- Edit
- Update
- Delete 

If you go to the controllers, you will see that all of those methods are in the there. Since we're developing a Rest API, we would not even need a route for create and edit, because those are meant to return a view with the forms for creating and editing the resource, respectively. As stated before we only need a list of authors, a list of books, and details of a specific book, so we use the  `only()` method to limit the resource routes.

Of course, we didn't need all of that boiler plate code, so might as well create each of those routes and methods from scratch, but I wanted to show you these methotds, because they save you time in your day-to-day.

Now, let's implement `index()` in the AuthorController, so go to `app/Http/Controllers/AuthorController.php` and add this code:

```php
public function index()
{
    $authors = Author::all();

    return response()->json($authors);
}
```

Since we only have 5 authors (created by the seeder, remember?), we would not even need pagination, so let's query all the authors.

In BookController we need to implement `index()` for the list of books and `show()` for the details of the specific book:

```php
public function index()
{
    $books = Book::with('author')->paginate(10);

    return response()->json($books);
}

public function show(Book $book)
{
    return response()->json($book);
}
```

The `with()` queries the relationship and already returns a book with its author.

> The string you pass to this method must be equal to the name of the method you gave to the relationship in the Book model.

Since we have at least 25 books, let's create a pagination query 10 books every time.

In the case of `show()`, Laravel already resolves the book id passed to the route and gives us the Book instance as an argument.

Now if you run Laravel's server using `php artisan serve`, you can access `http://localhost:8000/api/authors` or `http://localhost:8000/api/books` in your browser or in app like [Postman](http://insomnia.rest) or [Insomnia](http://insomnia.rest) and you will get a JSON response like this:

```json
{
  "current_page": 1,
  "data": [
    {
      "id": 1,
      "author_id": 6,
      "title": "Inventore voluptatem iure veniam quis nesciunt aut.",
      "price": "42.19",
      "created_at": "2020-05-16T17:39:22.000000Z",
      "updated_at": "2020-05-16T17:39:22.000000Z",
      "author": {
        "id": 6,
        "name": "Brandyn Gorczany",
        "created_at": "2020-05-16T17:39:22.000000Z",
        "updated_at": "2020-05-16T17:39:22.000000Z"
      }
    },
    ...
  ],
  "first_page_url": "http:\/\/localhost:8000\/api\/books?page=1",
  "from": 1,
  "last_page": 3,
  "last_page_url": "http:\/\/localhost:8000\/api\/books?page=3",
  "next_page_url": "http:\/\/localhost:8000\/api\/books?page=2",
  "path": "http:\/\/localhost:8000\/api\/books",
  "per_page": 10,
  "prev_page_url": null,
  "to": 10,
  "total": 25
}
```

If you want to access details of a book,  just go to `http://localhost:8000/api/books/1` where "1" is the id of the book you want to access. This will return this response:

```json
{
  "id": 1,
  "author_id": 6,
  "title": "Inventore voluptatem iure veniam quis nesciunt aut.",
  "price": "42.19",
  "created_at": "2020-05-16T17:39:22.000000Z",
  "updated_at": "2020-05-16T17:39:22.000000Z"
}
```

So, there you have it. It doesn't take too much time to create a Rest API with Laravel, as a bonus you already have factories and seeders setup to use in automated tests.