Skip to content

Last updated:

API Resources

API Resources transform Eloquent models into JSON responses. They control exactly what data is sent to the client and how relationships are serialized. The CPR backend has 46+ Resource classes.

Directory Structure

app/Http/Resources/
├── PatientResource.php
├── TransactionResource.php
├── TransactionItemResource.php
├── QueueTicketResource.php
├── BranchResource.php
├── DoctorResource.php
├── MedicineResource.php
├── PatientVisitResource.php
├── BillItemResource.php
├── PharmacyItemResource.php
├── DeliveryResource.php
├── PurchaseOrderResource.php
└── ... (46+ resources)

How They Work

Resources extend JsonResource and define a toArray() method that maps model fields to JSON output:

php
class PatientResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'pin' => $this->pin,
            'name' => $this->name,             // Computed attribute
            'first_name' => $this->first_name,
            'last_name' => $this->last_name,
            'middle_name' => $this->middle_name,
            'nick_name' => $this->nick_name,
            'birthdate' => $this->birthdate,
            'nationality' => $this->nationality,
            'occupation' => $this->occupation,
            'sex' => $this->sex,
            'civil_status' => $this->civil_status,
            'telephone' => $this->telephone,
            'mobile_phone' => $this->mobile_phone,
            'email' => $this->email,
            'photo_url' => $this->photo_path
                ? Storage::temporaryUrl($this->photo_path, now()->addMinutes(60))
                : null,
            'refered_by' => $this->refered_by,
            'referral_source_type' => $this->referral_source_type,
            'status' => $this->status,
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at,
        ];
    }
}

Key Patterns

Conditional Relationship Loading (whenLoaded)

Only includes a relation if it was eager-loaded — prevents accidental N+1 queries:

php
class TransactionResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'transaction_number' => $this->transaction_number,
            'branch_id' => $this->branch_id,
            'branch' => $this->whenLoaded('branch'),
            'patient_id' => $this->patient_id,
            'patient' => PatientResource::make($this->whenLoaded('patient')),
            'transaction_date' => $this->transaction_date?->format('Y-m-d'),
            'total_amount' => $this->total_amount,
            'payment_method_id' => $this->payment_method_id,
            'payment_method' => $this->whenLoaded('paymentMethod'),
            'status' => $this->status,
            'notes' => $this->notes,
            'items' => TransactionItemResource::collection($this->whenLoaded('items')),
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at,
        ];
    }
}

If the patient relation wasn't eager-loaded, it will be omitted from the response entirely (no lazy-load triggered).

Nested Resource Collections

Resources can nest other resources for related data:

php
'items' => TransactionItemResource::collection($this->whenLoaded('items')),

Enum Serialization

For models with enum casts, resources access enum values and helper methods:

php
class QueueTicketResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'ticket_number' => $this->ticket_number,
            'status' => $this->status?->value,           // Enum string value
            'status_label' => $this->status?->label(),    // Human-readable label
            'status_color' => $this->status?->color(),    // UI color code
            'priority_type' => $this->priority_type?->value,
            'priority_label' => $this->priority_type?->label(),
            'is_appointment' => $this->is_appointment,
            'patient' => PatientResource::make($this->whenLoaded('patient')),
            'service' => $this->whenLoaded('service'),
            // ... timestamps, user references
        ];
    }
}

Date Formatting

Dates are formatted explicitly when the default ISO 8601 format isn't desired:

php
'transaction_date' => $this->transaction_date?->format('Y-m-d'),

Temporary URLs

For file uploads stored on cloud storage:

php
'photo_url' => $this->photo_path
    ? Storage::temporaryUrl($this->photo_path, now()->addMinutes(60))
    : null,

Usage in Controllers

Single Resource

php
public function show(Patient $patient)
{
    return PatientResource::make($patient)
        ->additional(['message' => 'Patient retrieved successfully']);
}

Resource Collection (Paginated)

php
public function index(Request $request)
{
    $patients = $this->service->getPatients(
        $request->input('search'),
        $request->all(),
        $request->input('perPage', 15)
    );

    return PatientResource::collection($patients)
        ->additional(['message' => 'Patients retrieved successfully']);
}

The additional() method adds extra data alongside the data key in the response.

Created Response (201)

php
public function store(StorePatientDataRequest $request)
{
    $patient = $this->service->create($request->validated(), $branch);

    return PatientResource::make($patient)
        ->additional(['message' => 'Patient created successfully'])
        ->response()
        ->setStatusCode(201);
}

Creating a New Resource

bash
php artisan make:resource ExampleResource

Then define toArray():

php
class ExampleResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            // Map fields...
            'related' => RelatedResource::make($this->whenLoaded('related')),
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at,
        ];
    }
}

CPR - Clinical Patient Records