Run php artisan install:api to create routes/api.php. Routes in that file start with /api, so Route::get('/lessons', ...) answers at /api/lessons.
<?php
// routes/api.php
use App\Http\Controllers\Api\LessonController;
Route::get('/lessons', [LessonController::class, 'index']);
Route::post('/lessons', [LessonController::class, 'store']);Returning and receiving JSON
- Return a model or a collection from a controller and Laravel sends it as JSON.
$request->validate([...])checks the input. If it fails, an API client gets status 422 with the errors.response()->json($data, 201)sets the status code: 201 means “created”.
<?php
public function store(Request $request)
{
$data = $request->validate([
'title' => ['required', 'string', 'max:100'],
'summary' => ['required', 'string'],
]);
$lesson = Lesson::create($data);
return response()->json($lesson, 201);
}Test your API with a tool like Postman or Thunder Client, or call it from the Flutter lesson “Loading Data from an API”.
Code examples
<?php
// app/Http/Controllers/Api/LessonController.php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Lesson;
class LessonController extends Controller
{
public function index()
{
return Lesson::where('published', true)->get(['id', 'title']);
}
}Expected output
GET /api/lessons returns: [{"id":1,"title":"Routes"},{"id":2,"title":"Blade"}]get(['id', 'title']) selects only the columns the app needs, so the response stays small.
Common mistakes
Common mistake: Validation errors come back as a redirect, not JSON
Send the header Accept: application/json with your request, so Laravel answers with a 422 JSON error.
Common mistake: Sending every column, including private ones
Choose the columns (get(['id', 'title'])) or hide fields with $hidden on the model.
Check your understanding
3 quick questions about this lesson.