usmanzahid/service-response

A simple and effective way of communication between different services among your PHP application.

Maintainers

Package info

github.com/usmanx03/service-response

pkg:composer/usmanzahid/service-response

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.1.0 2026-03-02 05:55 UTC

This package is auto-updated.

Last update: 2026-03-02 05:56:22 UTC


README

A minimal and structured way to handle internal service communication in PHP applications.

Instead of returning null, false, throwing exceptions for expected failures, or using loosely structured arrays, ServiceResponse provides a consistent object containing success status, message, data, and errors. This standardization improves service orchestration, error handling, debugging, and API response consistency.

The class supports response chaining, allowing higher-level services to preserve and expose root causes from lower-level operations.

Includes

  • Core ServiceResponse class with fluent, chainable methods
  • Structured error aggregation
  • Previous response chaining for root-cause tracing
  • Helper functions for quick response creation
  • Consistent structure for success and failure cases

Response Structure

[
    'success' => true|false,
    'message' => ?string,
    'data' => mixed,
    'errors' => array,
]

Basic Usage

Success Response

return (new ServiceResponse())
    ->withMessage('Payment processed successfully')
    ->withData(['transaction_id' => $transactionId]);

Failure Response

return (new ServiceResponse())
    ->withSuccess(false)
    ->withMessage('Payment failed')
    ->withError('card', 'Card declined');

Adding Multiple Errors

return (new ServiceResponse())
    ->withSuccess(false)
    ->withMessage('Validation failed')
    ->withErrors([
        'email' => ['Email is required'],
        'password' => ['Password must be at least 8 characters'],
    ]);

Chaining Responses Between Services

When one service depends on another, you can attach the previous response to preserve context.

$paymentResponse = $paymentService->charge($order);

if ($paymentResponse->wasNotSuccessful()) {
    return (new ServiceResponse())
        ->withSuccess(false)
        ->withMessage('Order failed')
        ->withPrevious($paymentResponse);
}

return (new ServiceResponse())
    ->withMessage('Order completed')
    ->withPrevious($paymentResponse);

Accessing Aggregated Errors

$errors = $response->getAllErrors();

Getting the Root Cause

$root = $response->getRootCause();

Helper Functions

Helper functions provide a concise way to create responses without instantiating the class directly.

Success Helper

return service_response_success(
    data: ['user_id' => $user->id],
    message: 'User authenticated'
);

Failure Helper

return service_response_fail(
    errors: ['auth' => ['Invalid credentials']],
    message: 'Authentication failed'
);

From Exception

try {
    $gateway->charge($card);
} catch (Throwable $e) {
    return service_response_from_exception($e);
}

Real-World Examples

Authentication Service

public function authenticate(string $email, string $password): ServiceResponse
{
    $user = $this->repo->findByEmail($email);

    if (!$user || !$this->hasher->check($password, $user->password)) {
        return service_response_fail(
            ['auth' => ['Invalid credentials']],
            'Authentication failed'
        );
    }

    return service_response_success(
        ['user_id' => $user->id],
        'Authenticated successfully'
    );
}

Payment Service

public function charge(Order $order): ServiceResponse
{
    if ($order->total <= 0) {
        return service_response_fail(
            ['amount' => ['Invalid order total']],
            'Payment failed'
        );
    }

    $transactionId = $this->gateway->charge($order);

    return service_response_success(
        ['transaction_id' => $transactionId],
        'Payment processed'
    );
}

Orchestrating Multiple Services

$auth = $authService->authenticate($email, $password);

if ($auth->wasNotSuccessful()) {
    return $auth;
}

$payment = $paymentService->charge($order);

if ($payment->wasNotSuccessful()) {
    return (new ServiceResponse())
        ->withSuccess(false)
        ->withMessage('Checkout failed')
        ->withPrevious($payment);
}

return (new ServiceResponse())
    ->withMessage('Checkout completed')
    ->withPrevious($payment);

JSON Serialization

ServiceResponse implements JsonSerializable, allowing it to be safely encoded:

return json_encode($response);

// You can also do:
$response->jsonSerialize

Frameworks like Laravel will automatically serialize the response:

return response()->json($response);

Exceptionless Flow Control

Use the response status instead of exceptions for expected outcomes.

$response = $paymentService->charge($order);

if ($response->wasSuccessful()) {
    // proceed with fulfillment
    $fulfillmentService->dispatch($order);
} else {
    // log and return structured failure
    logger()->warning('Payment failed', $response->toArray());
    return $response;
}

Notes

  • Errors are grouped by key for predictable handling
  • getAllErrors() merges errors from chained responses
  • toArray() produces API-ready output
  • Responses can be safely returned across service boundaries