Skip to content

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