API
A mobile app or a React front end needs data in JSON rather than HTML pages. Laravel returns JSON with almost no extra code: a model returned from a controller turns into it by itself.
API routes
In recent Laravel versions the API routes file is created with a command:
php artisan install:apiIt adds the routes/api.php file. Every address in it starts with /api:
use App\Http\Controllers\Api\PostController;
use Illuminate\Support\Facades\Route;
Route::apiResource('posts', PostController::class);apiResource registers five routes: list, view, create, update and delete.
The controller
php artisan make:controller Api/PostController --apiA model or a collection returned from a method automatically becomes JSON:
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Post;
class PostController extends Controller
{
public function index()
{
return Post::latest()->paginate(20);
}
public function show(Post $post)
{
return $post;
}
}The Post $post parameter is route model binding: Laravel finds the record by the identifier in the address or returns 404.
Creating a record
public function store(Request $request)
{
$data = $request->validate([
'title' => 'required|max:255',
'body' => 'required',
]);
$post = Post::create($data);
return response()->json($post, 201);
}The 201 code means "created". If validation fails, the API client receives a 422 response with a list of errors in JSON — there is no redirect to a form.
API resources
Returning the whole model is inconvenient: every column, service ones included, ends up in the response. A resource describes exactly what the client sees:
php artisan make:resource PostResourcenamespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class PostResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'published_at' => $this->created_at->toDateString(),
];
}
}return new PostResource($post);
return PostResource::collection(Post::paginate(20));Deleting
public function destroy(Post $post)
{
$post->delete();
return response()->noContent();
}noContent() sends the 204 code — "done, no response body".
Authentication
The install:api command installs the Sanctum package. The client sends a token in the Authorization header, and routes are protected with middleware:
Route::middleware('auth:sanctum')->group(function () {
Route::apiResource('posts', PostController::class)->except(['index', 'show']);
});Common mistake
The client must send the Accept: application/json header. Without it Laravel treats the request as a regular one and answers a validation failure with a redirect instead of JSON with the errors.