Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Status Code Laravel Package

teapot/status-code

teapot/status-code gives Laravel and PHP apps a clean way to reference HTTP status codes. Replace magic numbers with readable constants and helpers in responses, middleware, and tests, keeping your API consistent and self-documenting, with a touch of teapot humor.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require teapot/status-code

Before writing any code, do three things:

  1. Check the PHP constraint in composer.json. This package is built around PHP 8.1+ enums, so if any of your services are still on 8.0 this is a non-starter.
  2. Open the enum definition first (src/) — it is the entire public API. Confirm the case naming convention (Status::NOT_FOUND vs Status::NotFound), the backing type (almost certainly int), and which helper methods exist (phrase(), reason(), isSuccess(), isClientError(), family() — names vary between packages). Thirty seconds here saves you a BadMethodCallException later.
  3. Grep your codebase for magic numbers — Response::HTTP_* constants, raw 200/404/422 literals, and abort(404). That list is your migration backlog and tells you where the package will actually pay off.

First use case: a controller (or a base ApiController) returning a created resource.

use Teapot\StatusCode\Status;   // verify exact namespace in src/

return response()->json($user, Status::CREATED->value);

If that one line reads better than 201 to you, the package earns its place. If it doesn't, stop here — Laravel's Illuminate\Http\Response::HTTP_CREATED already exists and adds zero dependencies.

Implementation Patterns

Treat it as a type, not a constant table. The real win is signatures that can't be passed garbage:

function respond(array $payload, Status $status = Status::OK): JsonResponse
{
    return response()->json($payload, $status->value);
}

Now respond($data, 999) is a TypeError at the call site rather than a broken response at runtime.

Custom exception carrying a status. This is the highest-leverage pattern in a Laravel app:

class ApiException extends \RuntimeException
{
    public function __construct(
        string $message,
        public readonly Status $status = Status::BAD_REQUEST,
        public readonly array $context = [],
    ) {
        parent::__construct($message);
    }
}

Then in bootstrap/app.php (Laravel 11+) or app/Exceptions/Handler.php:

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->render(fn (ApiException $e) => response()->json([
        'message' => $e->getMessage(),
    ], $e->status->value));
})

Every throw new ApiException('...', Status::CONFLICT) in your domain layer now renders correctly with no controller-level try/catch. Validate this with a Feature test per status you actually use.

Override failedValidation in a base FormRequest so 422s come from one place:

protected function failedValidation(Validator $validator)
{
    throw new ValidationException($validator, response()->json([
        'errors' => $validator->errors(),
    ], Status::UNPROCESSABLE_ENTITY->value));
}

Use it in abort() and middleware. abort(Status::FORBIDDEN->value) in a Gate::authorize fallback; a maintenance middleware returning Status::SERVICE_UNAVAILABLE->value with a Retry-After header.

Use it in assertions. $response->assertStatus(Status::CREATED->value) — self-documenting tests that fail loudly if someone "tidies" 201 into 200.

Bridge to OpenAPI/docs. One match or array map from Status cases to descriptions keeps your generated docs and your runtime in sync instead of maintaining two lists of numbers.

DB casts. For columns like last_response_status, an Eloquent enum cast to the package enum gives you $model->last_response_status->value on read and validation on write.

Gotchas and Tips

  • ->value is mandatory at the Laravel boundary. response()->json($data, Status::OK) will not work — Symfony's Response wants an int. Do the unwrapping in one helper and never scatter ->value through your controllers.
  • Enums are not extensible. You can't subclass a pure enum, so you can't add domain-specific cases (e.g. 499 Client Closed Request, or internal-only codes). Check coverage before committing; if you need extras, wrap it in your own App\Http\Status enum or a static helper rather than forking.
  • Don't compare against ints. $status === 200 is always false. Compare $status->value === 200 or $status === Status::OK. This is the most likely silent bug in a migration.
  • json_encode of a backed enum emits its scalar value, which is convenient for responses but surprising if you expected the case name — and pure (non-backed) enums throw on encode. Verify which you have.
  • Reason phrases are English and not user-facing. ->phrase() is for logs, dev tools, and docs. Anything a customer reads goes through lang/.
  • Duplication with Response::HTTP_*. Pick one convention for the whole team and enforce it in code review, otherwise you have two canonical sources of truth. Realistically, keep the enum for new domain/signature code and leave existing constants alone.
  • Small package, near-zero adoption (45 stars, 0 dependents). Pin the version ("teapot/status-code": "^1.0") and read the changelog before upgrading, because you have no downstream ecosystem to signal breakage. The surface is tiny, so worst case you vendor the enum into your app in an afternoon.
  • Verify method names against source, not the README. Status-code packages in this space disagree on phrase() vs reason(), and on whether family helpers exist at all. If a helper you need is missing, add it as a method on a StatusHelper class in your app rather than requesting it upstream.
  • Watch for the 3xx footgun — returning Status::FOUND from a JSON API instead of a documented Location header. The enum makes the number prettier, not the semantics correct.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package