How to Build a CRUD REST API in Laravel

A REST API is the main foundation in modern application development, both for mobile apps and separate frontends (SPAs). Laravel provides very complete tools for building clean and...

How to Build a CRUD REST API in Laravel
Advertisement

A REST API is the main foundation in modern application development, both for mobile apps and separate frontends (SPAs). Laravel provides very complete tools for building clean and structured REST APIs. In this tutorial, you'll learn to build a complete CRUD (Create, Read, Update, Delete) REST API using Laravel 10/11.

Preparing the Laravel Project

Make sure you already have a Laravel project. If not, create one with the following command:

composer create-project laravel/laravel laravel-api
cd laravel-api
php artisan serve

Create the model, migration, and resource controller all at once with a single command:

Advertisement
php artisan make:model Product -mcr

The -m flag creates the migration, -c creates the controller, and -r makes it a resource controller.

Creating the Migration and Model

Open the newly created migration file in database/migrations/ and add the columns you need:

public function up(): void
{
    Schema::create('products', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->text('description')->nullable();
        $table->decimal('price', 10, 2);
        $table->integer('stock')->default(0);
        $table->timestamps();
    });
}

Then edit the model app/Models/Product.php:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    protected $fillable = [
        'name',
        'description',
        'price',
        'stock',
    ];
}

Run the migration:

Advertisement
php artisan migrate

Defining the API Routes

Open the routes/api.php file and add the resource route:

<?php

use App\Http\Controllers\ProductController;
use Illuminate\Support\Facades\Route;

Route::apiResource('products', ProductController::class);

The apiResource command automatically creates 5 routes: index, store, show, update, and destroy. You can check them with:

php artisan route:list --path=api

Creating an API Resource for the Response

Use a Laravel API Resource so the JSON response format is consistent:

php artisan make:resource ProductResource

Edit app/Http/Resources/ProductResource.php:

Advertisement
<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class ProductResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id'          => $this->id,
            'name'        => $this->name,
            'description' => $this->description,
            'price'       => (float) $this->price,
            'stock'       => $this->stock,
            'created_at'  => $this->created_at->toDateTimeString(),
        ];
    }
}

Writing the Controller Logic

Open app/Http/Controllers/ProductController.php and fill in each method:

<?php

namespace App\Http\Controllers;

use App\Http\Resources\ProductResource;
use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;

class ProductController extends Controller
{
    public function index(): JsonResponse
    {
        $products = Product::latest()->paginate(10);
        return ProductResource::collection($products)->response();
    }

    public function store(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'name'        => 'required|string|max:255',
            'description' => 'nullable|string',
            'price'       => 'required|numeric|min:0',
            'stock'       => 'required|integer|min:0',
        ]);

        $product = Product::create($validated);

        return (new ProductResource($product))
            ->response()
            ->setStatusCode(201);
    }

    public function show(Product $product): JsonResponse
    {
        return (new ProductResource($product))->response();
    }

    public function update(Request $request, Product $product): JsonResponse
    {
        $validated = $request->validate([
            'name'        => 'sometimes|string|max:255',
            'description' => 'nullable|string',
            'price'       => 'sometimes|numeric|min:0',
            'stock'       => 'sometimes|integer|min:0',
        ]);

        $product->update($validated);

        return (new ProductResource($product))->response();
    }

    public function destroy(Product $product): JsonResponse
    {
        $product->delete();

        return response()->json([
            'message' => 'Product deleted successfully.',
        ]);
    }
}

Testing the API with Postman or cURL

Example requests using cURL:

# GET all products
curl -X GET http://localhost:8000/api/products \
  -H "Accept: application/json"

# POST a new product
curl -X POST http://localhost:8000/api/products \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name":"Laptop","price":12000000,"stock":5}'

# PUT update a product
curl -X PUT http://localhost:8000/api/products/1 \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"price":11500000}'

# DELETE a product
curl -X DELETE http://localhost:8000/api/products/1 \
  -H "Accept: application/json"

Handling Errors with a Consistent Response

For neat error handling, you can add a response helper in the controller or create a dedicated trait:

// Success response
return response()->json([
    'success' => true,
    'data'    => new ProductResource($product),
    'message' => 'Product created successfully.',
], 201);

// Validation failure response (automatic by Laravel)
// Status 422 Unprocessable Entity

Conclusion

You've successfully built a complete CRUD REST API in Laravel using a Resource Controller, an API Resource for JSON formatting, and Laravel's built-in validation. The next step is to add authentication using Laravel Sanctum so your API endpoints are protected. With this structure, your API is ready to be consumed by a React or Vue frontend or a mobile app.

Advertisement
rest api laravel crud api laravel laravel resource controller laravel api route laravel json response tutorial api laravel
Share this article
Back to Blog
🚀 Partner Recommendation

Need Premium Source Code & Business Apps?

Access Laravel applications, POS systems, School Management, Clinic Software, ERP solutions, and ready-to-use premium source code at GudangCode.

GudangCode
  • ✔ Premium Source Code
  • ✔ Ready-to-Use Systems
  • ✔ Lifetime Updates
  • ✔ Lifetime Membership
  • ✔ Daily App Updates
Join Membership →
Advertisement
Latest Articles
Oct 16, 2026
Oct 15, 2026
Oct 14, 2026
Oct 13, 2026
Oct 11, 2026
Advertisement