Laravel中构建RESTful API返回指定层级JSON格式的实现
Alright, let's break this down step by step to build the Laravel RESTful API that returns your desired JSON structure. First, we'll make sure our model relationships are set up correctly, then handle the data formatting in the controller, and finally wire up the route.
First off, Class is a reserved keyword in PHP, so I'll rename that model to SchoolClass to prevent errors (we'll still map it to your existing classes database table). Here's how each model should look:
School Model (app/Models/School.php)
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; class School extends Model { protected $fillable = ['school_name']; // One School has many Classes public function classes(): HasMany { return $this->hasMany(SchoolClass::class, 'school_id'); } }
SchoolClass Model (app/Models/SchoolClass.php)
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; class SchoolClass extends Model { protected $table = 'classes'; // Map to your existing `classes` table protected $fillable = ['school_id', 'class']; // A Class belongs to one School public function school(): BelongsTo { return $this->belongsTo(School::class, 'school_id'); } // One Class has many Students public function students(): HasMany { return $this->hasMany(Student::class, 'class_id'); } }
Student Model (app/Models/Student.php)
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; class Student extends Model { protected $fillable = ['class_id', 'Student_fname', 'Student_lname']; // A Student belongs to one Class public function schoolClass(): BelongsTo { return $this->belongsTo(SchoolClass::class, 'class_id'); } }
Let's create a dedicated API controller to handle the data fetching and formatting. Run this command first to generate it:
php artisan make:controller Api/SchoolController
Now open app/Http/Controllers/Api/SchoolController.php and add this logic. We'll use eager loading to avoid the N+1 query problem, then manually restructure the data to match your required JSON format:
namespace App\Http\Controllers\Api; use App\Http\Controllers\Controller; use App\Models\School; class SchoolController extends Controller { public function index() { // Eager load related classes and students to optimize performance $schools = School::with('classes.students')->get(); // Format the data to match your desired structure $formattedOutput = []; foreach ($schools as $school) { $classData = []; foreach ($school->classes as $class) { $studentData = []; foreach ($class->students as $student) { $studentData[$student->id] = [ 'Student_fname' => $student->Student_fname, 'Student_lname' => $student->Student_lname ]; } $classData[$class->id] = [ 'class_id' => $class->id, 'school_id' => $class->school_id, 'class' => $class->class, 'Student' => $studentData ]; } $formattedOutput[$school->id] = [ 'school_id' => $school->id, 'school_name' => $school->school_name, 'Class' => $classData ]; } // Wrap the formatted data in an array as per your example return response()->json([$formattedOutput]); } }
Add this route to routes/api.php to make your endpoint accessible:
use App\Http\Controllers\Api\SchoolController; // GET endpoint to fetch the structured school data Route::get('/schools', [SchoolController::class, 'index']);
- Double-check your database table columns match the
fillableproperties in the models (e.g.,schoolstable should haveidandschool_name,classeshasid,school_id,class,studentshasid,class_id,Student_fname,Student_lname). - If you only need data for a single school, modify the query to
School::where('id', $schoolId)->with('classes.students')->first()and adjust the formatting loop accordingly. - Eager loading (
with('classes.students')) is critical here—it prevents Laravel from running hundreds of extra queries when fetching related data.
内容的提问来源于stack exchange,提问作者Animesh Pandey

