Laravel REST API
A Laravel REST API lets mobile apps, single-page frontends and other services talk to your application using JSON. Laravel 11 makes this easy with api routes, resource controllers and API resource classes that shape your JSON output.
Enabling API Routes
Laravel 11 does not include routes/api.php by default. This command creates it and installs Sanctum for token authentication. Routes in this file are automatically prefixed with /api.
php artisan install:apiINFO API scaffolding installed. Please add the [Laravel\Sanctum\HasApiTokens] trait to your User model.
API Resource Routes and Controller
<?php
// routes/api.php
Route::apiResource('products', ProductController::class);
// php artisan make:controller Api/ProductController --api --model=Product
class ProductController extends Controller
{
public function index()
{
return ProductResource::collection(Product::latest()->paginate(20));
}
public function store(StoreProductRequest $request)
{
$product = Product::create($request->validated());
return (new ProductResource($product))->response()->setStatusCode(201);
}
public function show(Product $product)
{
return new ProductResource($product);
}
public function update(StoreProductRequest $request, Product $product)
{
$product->update($request->validated());
return new ProductResource($product);
}
public function destroy(Product $product)
{
$product->delete();
return response()->noContent();
}
}GET /api/products -> 200 list (paginated) POST /api/products -> 201 created GET /api/products/5 -> 200 single product PUT /api/products/5 -> 200 updated DELETE /api/products/5 -> 204 No Content
Shaping JSON With API Resources
An API resource controls exactly which fields leave your server and how they are named, so database changes do not break clients.
php artisan make:resource ProductResource
<?php
class ProductResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'price' => (float) $this->price,
'in_stock' => $this->stock > 0,
'category' => $this->whenLoaded('category', fn () => $this->category->name),
'created_at' => $this->created_at->toIso8601String(),
];
}
}{
"data": {
"id": 5,
"name": "Green Tea",
"price": 4.5,
"in_stock": true,
"created_at": "2026-10-31T10:00:00+00:00"
}
}Status Codes and Errors
- 200 OK for successful reads and updates
- 201 Created after POST creates a record
- 204 No Content after a delete
- 401 Unauthenticated when no valid token is sent
- 403 Forbidden when a policy denies access
- 404 Not Found from route model binding
- 422 Unprocessable Content for validation errors
- 429 Too Many Requests from rate limiting
Testing the API With curl
Always send Accept: application/json so Laravel returns JSON errors instead of HTML redirects.
curl -X POST http://localhost:8000/api/products \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name":"Green Tea","price":4.5,"stock":20}'{"data":{"id":5,"name":"Green Tea","price":4.5,"in_stock":true,"created_at":"2026-10-31T10:00:00+00:00"}}Frequently asked questions
How do I create an API in Laravel 11?
Run php artisan install:api, define routes in routes/api.php (for example Route::apiResource), create controllers that return API resources, and protect them with Sanctum.
What is the difference between resource and apiResource?
apiResource registers the same CRUD routes but leaves out create and edit, which only exist to show HTML forms.
Why does my Laravel API return HTML instead of JSON?
The client did not send Accept: application/json, so Laravel treated it as a browser request. Add the header to your requests.