{"id":51966848,"url":"https://github.com/yoosuf/laravel-api","last_synced_at":"2026-07-29T18:01:27.130Z","repository":{"id":371979088,"uuid":"1303490036","full_name":"yoosuf/laravel-api","owner":"yoosuf","description":"High-performance Laravel API toolkit with OpenAPI 3 generation, interactive docs UI, and consistent response helpers.","archived":false,"fork":false,"pushed_at":"2026-07-18T03:15:47.000Z","size":131,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-18T05:10:19.971Z","etag":null,"topics":["api","api-docs","laravel","laravel-package","openapi","openapi3","php","redoc","rest-api","swagger"],"latest_commit_sha":null,"homepage":"https://packagist.org/packages/yoosuf/laravel-api","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yoosuf.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":"SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-17T03:00:48.000Z","updated_at":"2026-07-18T03:15:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/yoosuf/laravel-api","commit_stats":null,"previous_names":["yoosuf/laravel-api"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/yoosuf/laravel-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoosuf%2Flaravel-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoosuf%2Flaravel-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoosuf%2Flaravel-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoosuf%2Flaravel-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yoosuf","download_url":"https://codeload.github.com/yoosuf/laravel-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoosuf%2Flaravel-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36043168,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-29T02:00:04.910Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","api-docs","laravel","laravel-package","openapi","openapi3","php","redoc","rest-api","swagger"],"created_at":"2026-07-29T18:01:26.126Z","updated_at":"2026-07-29T18:01:27.122Z","avatar_url":"https://github.com/yoosuf.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# yoosuf/laravel-api\n\nProduction-ready Laravel API toolkit: consistent response envelopes, structured error formats, OpenAPI 3 generation, request correlation, API versioning, exception rendering, paginator adapters, ETag helpers, security headers, and a health check endpoint — all in one package.\n\n## Features\n\n### Response building\n- Unified `ApiResponder` with every standard HTTP status shortcut (200–503)\n- Two error formats: `envelope` (`ok / type / message / data / errors`) and `structured` (`error.code / message / target / details / innererror`)\n- Paginated collection responses with OData-lite shape (`value / @count / @nextLink / @prevLink`) and RFC 5988 `Link` header\n- `LengthAwarePaginator` and `CursorPaginator` adapters (`fromPaginator()` / `fromCursorPaginator()`)\n- `Location` header on `created()` and `accepted()` (RFC 7231)\n- `Retry-After` header on 429 / 503\n- `X-RateLimit-Limit / Remaining / Reset` on 429\n- ETag generation, conditional-request checking, and `304 Not Modified`\n- Configurable envelope keys, default messages, and pagination keys\n\n### Middleware\n- `laravel-api.force-json` — forces `Accept: application/json` so exceptions render as JSON, not HTML\n- `laravel-api.request-id` — attaches `X-Request-ID` and `X-Correlation-ID` to every request and response\n- `laravel-api.security-headers` — `X-Content-Type-Options`, `X-Frame-Options`, `Cache-Control`, `Referrer-Policy`\n- `laravel-api.versioning` — reads and validates `?api-version=` or `Api-Version:` header\n- `laravel-api.deprecation` — sets `Deprecation:` and `Sunset:` headers on retiring routes\n\n### Exception handling\n- `ApiExceptionRenderer` converts `AuthenticationException`, `AuthorizationException`, `ValidationException`, `ModelNotFoundException`, `HttpException`, and generic `Throwable` into consistent API responses\n- Opt-in auto-registration via `LARAVEL_API_EXCEPTIONS_AUTO_RENDER=true`\n\n### OpenAPI generation\n- Route-driven OpenAPI 3.0.3 spec from Laravel routes\n- Tags auto-inferred from controller class name (`OrderController` → `orders`)\n- Auth middleware (`auth:sanctum`, `auth:api`, etc.) → `security: [{ bearerAuth: [] }]`\n- Standard reusable response definitions auto-added to `components.responses`\n- Standard error schemas (`ErrorEnvelope`, `StructuredError`) in `components.schemas`\n- `FormRequest` rules → `requestBody` schema inference\n- `JsonResource` / `ResourceCollection` → response schema inference\n- JSON and YAML export, runtime endpoints, optional Swagger UI / Redoc\n- Spec caching with configurable store and TTL\n\n### Health check\n- `GET /_health` endpoint (configurable route, middleware, and on/off toggle)\n\n### Testing utilities\n- `ApiResponseAssertions` trait for fluent test assertions (`assertApiSuccess`, `assertApiPaginated`, `assertStructuredError`, etc.)\n\n---\n\n## Installation\n\n### Path repository (monorepo / local)\n\nAdd the path repository in root `composer.json`:\n\n```json\n{\n  \"type\": \"path\",\n  \"url\": \"packages/yoosuf/laravel-api\",\n  \"options\": { \"symlink\": true }\n}\n```\n\nRequire and publish:\n\n```bash\ncomposer require yoosuf/laravel-api:*\nphp artisan vendor:publish --tag=laravel-api-config\n```\n\n### Packagist (once published)\n\n```bash\ncomposer require yoosuf/laravel-api\nphp artisan vendor:publish --tag=laravel-api-config\n```\n\n---\n\n## Quick start\n\n### 1. Register recommended middleware\n\nIn `app/Http/Kernel.php`, add to the `api` middleware group:\n\n```php\n'api' =\u003e [\n    \\Yoosuf\\LaravelApi\\Http\\Middleware\\ForceJsonMiddleware::class,\n    \\Yoosuf\\LaravelApi\\Http\\Middleware\\RequestIdMiddleware::class,\n    \\Yoosuf\\LaravelApi\\Http\\Middleware\\SecurityHeadersMiddleware::class,\n    'throttle:api',\n    \\Illuminate\\Routing\\Middleware\\SubstituteBindings::class,\n],\n```\n\nOr use the named aliases registered by the package:\n\n```php\n'api' =\u003e [\n    'laravel-api.force-json',\n    'laravel-api.request-id',\n    'laravel-api.security-headers',\n    'throttle:api',\n    \\Illuminate\\Routing\\Middleware\\SubstituteBindings::class,\n],\n```\n\n### 2. Auto-register exception rendering (optional)\n\nIn `.env`:\n\n```\nLARAVEL_API_EXCEPTIONS_AUTO_RENDER=true\n```\n\nOr register manually in `AppServiceProvider::boot()`:\n\n```php\napp(\\Yoosuf\\LaravelApi\\Exceptions\\ApiExceptionRenderer::class)-\u003eregister();\n```\n\nThis converts `AuthenticationException`, `ValidationException`, `ModelNotFoundException`, and `HttpException` into consistent JSON API responses automatically.\n\n### 3. Use `HasApiResponses` in controllers\n\n```php\nuse Yoosuf\\LaravelApi\\Concerns\\HasApiResponses;\n\nclass OrderController extends Controller\n{\n    use HasApiResponses;\n\n    public function index(): JsonResponse\n    {\n        $orders = Order::paginate(20);\n        return $this-\u003efromPaginator($orders);\n    }\n\n    public function store(StoreOrderRequest $request): JsonResponse\n    {\n        $order = Order::create($request-\u003evalidated());\n        return $this-\u003ecreated($order, 'Order created', null, route('orders.show', $order));\n    }\n\n    public function show(Order $order): JsonResponse\n    {\n        $response = $this-\u003esuccess($order);\n        return $this-\u003ewithEtag($response);\n    }\n\n    public function destroy(Order $order): JsonResponse\n    {\n        $order-\u003edelete();\n        return $this-\u003enoContent();\n    }\n}\n```\n\n### 4. Or use the Facade / helpers directly\n\n```php\nuse Yoosuf\\LaravelApi\\Facades\\ApiResponse;\n\n// Facade\nreturn ApiResponse::success($data, 'Fetched');\nreturn ApiResponse::fromPaginator($paginator);\nreturn ApiResponse::validation('Invalid input', $errors);\n\n// Global helpers\nreturn response_success($data, 'Fetched');\nreturn response_failed('Bad input', 422, $errors);\nreturn api_paginated($items, $total, $nextUrl);\n```\n\n---\n\n## Response formats\n\n### Envelope format (default)\n\n**Success:**\n```json\n{\n  \"ok\": true,\n  \"type\": \"success\",\n  \"message\": \"Fetched\",\n  \"data\": { \"id\": 1, \"name\": \"Order #1\" },\n  \"meta\": {}\n}\n```\n\n**Error:**\n```json\n{\n  \"ok\": false,\n  \"type\": \"failed\",\n  \"message\": \"Validation failed\",\n  \"data\": null,\n  \"meta\": {},\n  \"errors\": {\n    \"email\": [\"The email field is required.\"]\n  }\n}\n```\n\n### Structured format\n\nSet `LARAVEL_API_ERROR_FORMAT=structured` to use the structured error format for all error responses:\n\n```json\n{\n  \"error\": {\n    \"code\": \"UnprocessableEntity\",\n    \"message\": \"Validation failed\",\n    \"target\": null,\n    \"details\": [\n      { \"code\": \"ValidationError\", \"message\": \"The email field is required.\", \"target\": \"email\" }\n    ]\n  }\n}\n```\n\nUse `structuredError()` explicitly regardless of format setting:\n\n```php\nreturn $this-\u003estructuredError('ResourceNotFound', 'Order not found', 404, 'orderId');\n```\n\n### Paginated response\n\n```json\n{\n  \"value\": [ { \"id\": 1 }, { \"id\": 2 } ],\n  \"@count\": 100,\n  \"@nextLink\": \"https://api.example.com/orders?page=3\",\n  \"@prevLink\": \"https://api.example.com/orders?page=1\"\n}\n```\n\nResponse also includes `Link: \u003curl\u003e; rel=\"next\", \u003curl\u003e; rel=\"prev\"` header (RFC 5988).\n\n---\n\n## All response methods\n\n### Success\n\n| Method | Status | Notes |\n|---|---|---|\n| `success($data, $message, $status, $meta)` | 200 | Base success |\n| `created($data, $message, $meta, $location)` | 201 | Sets `Location` header |\n| `accepted($data, $message, $meta, $location)` | 202 | Sets `Location` header |\n| `noContent()` | 204 | Empty body |\n| `paginated($items, $total, $nextLink, $prevLink)` | 200 | OData-lite + `Link` header |\n| `fromPaginator($paginator)` | 200 | From `LengthAwarePaginator` |\n| `fromCursorPaginator($paginator)` | 200 | From `CursorPaginator` (no `@count`) |\n\n### Client errors (4xx)\n\n| Method | Status |\n|---|---|\n| `badRequest($message, $errors, $meta)` | 400 |\n| `unauthorized($message, $errors, $meta)` | 401 |\n| `forbidden($message, $errors, $meta)` | 403 |\n| `notFound($message, $errors, $meta)` | 404 |\n| `conflict($message, $errors, $meta)` | 409 |\n| `gone($message, $errors, $meta)` | 410 |\n| `validation($messageOrException, $errors, $meta)` | 422 |\n| `unprocessable($message, $errors, $meta)` | 422 |\n| `locked($message, $errors, $meta)` | 423 |\n| `tooManyRequests($message, $errors, $meta, $retryAfter, $limit, $remaining, $reset)` | 429 |\n\n### Server errors (5xx)\n\n| Method | Status |\n|---|---|\n| `error($message, $status, $errors, $meta)` | 5xx |\n| `notImplemented($message, $errors, $meta)` | 501 |\n| `serviceUnavailable($message, $errors, $meta, $retryAfter)` | 503 |\n\n### ETag / conditional requests\n\n```php\n$response = $this-\u003esuccess($data);\n$response = $this-\u003ewithEtag($response);          // adds ETag header\nreturn $this-\u003echeckEtag($request, $response);    // returns 304 if If-None-Match matches\n```\n\n---\n\n## Middleware reference\n\n### ForceJsonMiddleware\n\nForces `Accept: application/json` so every request — including framework-level errors — returns JSON.\n\n```php\n// Kernel.php api group\n'laravel-api.force-json',\n```\n\n### RequestIdMiddleware\n\nAttaches `X-Request-ID` and `X-Correlation-ID` to every request and response.\n\n```\nLARAVEL_API_REQUEST_ID_ENABLED=true\nLARAVEL_API_REQUEST_ID_HEADER=X-Request-ID\nLARAVEL_API_CORRELATION_HEADER=X-Correlation-ID\n```\n\n### SecurityHeadersMiddleware\n\nAdds `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `Cache-Control: no-store`, `Referrer-Policy: strict-origin`.\n\n### ApiVersionMiddleware\n\nReads `?api-version=` or `Api-Version:` header. Returns a structured 400 for unsupported versions.\n\n```\nLARAVEL_API_VERSIONING_ENABLED=true\nLARAVEL_API_VERSION_CURRENT=1.0\n```\n\nConfig: `laravel-api.versioning.supported = ['1.0', '2.0']`\n\n### DeprecationMiddleware\n\nSignals deprecation and removal date on a route group.\n\n```php\nRoute::middleware(['laravel-api.deprecation:2025-01-01,2026-01-01'])-\u003egroup(function () {\n    // deprecated routes\n});\n```\n\nSets `Deprecation:` and `Sunset:` response headers automatically.\n\n---\n\n## Exception rendering\n\n```php\n// AppServiceProvider::boot()\napp(\\Yoosuf\\LaravelApi\\Exceptions\\ApiExceptionRenderer::class)-\u003eregister();\n```\n\n| Exception | Status |\n|---|---|\n| `AuthenticationException` | 401 |\n| `AuthorizationException` | 403 |\n| `ValidationException` | 422 with full error bag |\n| `ModelNotFoundException` | 404 with model name |\n| `HttpException` | matching status |\n| `Throwable` | 500 (message hidden in production, shown with `APP_DEBUG=true`) |\n\nOnly renders for requests that send `Accept: application/json` or match `api/*`.\n\n---\n\n## Health check\n\nEnabled by default at `GET /_health`:\n\n```json\n{ \"status\": \"ok\", \"timestamp\": \"2026-07-18T08:00:00Z\" }\n```\n\n```\nLARAVEL_API_HEALTH_ENABLED=true\nLARAVEL_API_HEALTH_ROUTE=_health\n```\n\n---\n\n## OpenAPI generation\n\n### Generate files\n\n```bash\nphp artisan api:openapi\nphp artisan api:openapi --format=json\nphp artisan api:openapi --format=yaml --output=docs/openapi.v2.yaml\nphp artisan api:openapi --prefix=/api/v1\nphp artisan api:openapi --include-route=orders.index --middleware=api\n```\n\n### Auto-generated spec features\n\nEvery generated spec includes:\n\n- **Tags** inferred from controller name (`OrderController` → `orders`)\n- **`bearerAuth` security scheme** when any route uses auth middleware\n- **`security: [{ bearerAuth: [] }]`** on auth-gated operations\n- **Standard response refs**: `401`, `403`, `404` (path-param routes), `422` (POST/PUT/PATCH), `429`, `500` on every operation\n- **`ErrorEnvelope`** and **`StructuredError`** schemas in `components.schemas`\n- `requestBody` inferred from `FormRequest` rules\n- Response schemas inferred from `JsonResource` / `ResourceCollection` return types\n\n### Runtime endpoints\n\n```\nGET /openapi.json\nGET /openapi.yaml\nGET /api-docs       # optional Swagger UI or Redoc\nGET /_health\n```\n\n### Schema providers\n\n```php\n// config/laravel-api.php\n'providers' =\u003e [\n    App\\OpenApi\\Providers\\OrderSchemaProvider::class,\n],\n```\n\n```php\nclass OrderSchemaProvider implements SchemaProvider\n{\n    public function schemas(): array\n    {\n        return [\n            'Order' =\u003e [\n                'type' =\u003e 'object',\n                'properties' =\u003e [\n                    'id'     =\u003e ['type' =\u003e 'integer'],\n                    'status' =\u003e ['type' =\u003e 'string', 'enum' =\u003e ['draft', 'placed', 'fulfilled']],\n                ],\n            ],\n        ];\n    }\n}\n```\n\n### Operation overrides\n\n```php\n'overrides' =\u003e [\n    'routes' =\u003e [\n        'orders.store' =\u003e ['post' =\u003e ['summary' =\u003e 'Place an order', 'tags' =\u003e ['orders']]],\n    ],\n    'actions' =\u003e [\n        'App\\Http\\Controllers\\OrderController@store' =\u003e [\n            'post' =\u003e ['x-internal' =\u003e true],\n        ],\n    ],\n],\n```\n\n---\n\n## Testing with ApiResponseAssertions\n\nAdd the trait to your test case for fluent API response assertions:\n\n```php\nuse Yoosuf\\LaravelApi\\Testing\\ApiResponseAssertions;\n\nclass OrderTest extends TestCase\n{\n    use ApiResponseAssertions;\n\n    public function test_index(): void\n    {\n        $response = $this-\u003egetJson('/api/orders');\n        $this-\u003eassertApiPaginated($response);\n    }\n\n    public function test_store_validation(): void\n    {\n        $response = $this-\u003epostJson('/api/orders', []);\n        $this-\u003eassertApiValidationError($response, 'amount');\n    }\n\n    public function test_store_success(): void\n    {\n        $response = $this-\u003epostJson('/api/orders', ['amount' =\u003e 100]);\n        $this-\u003eassertApiCreated($response);\n        $this-\u003eassertApiDataKey($response, 'id', 1);\n    }\n\n    public function test_rate_limiting(): void\n    {\n        $response = $this-\u003egetJson('/api/orders');\n        $this-\u003eassertApiTooManyRequests($response, 60); // asserts Retry-After: 60\n    }\n}\n```\n\nAvailable assertions:\n\n| Method | Description |\n|---|---|\n| `assertApiSuccess($response, $status)` | ok=true, envelope structure |\n| `assertApiCreated($response)` | 201 + envelope |\n| `assertApiAccepted($response)` | 202 + envelope |\n| `assertApiNoContent($response)` | 204 |\n| `assertApiPaginated($response)` | `value` + `@count` |\n| `assertApiError($response, $status)` | ok=false |\n| `assertApiValidationError($response, $field)` | 422 + optional field check |\n| `assertApiUnauthorized($response)` | 401 |\n| `assertApiForbidden($response)` | 403 |\n| `assertApiNotFound($response)` | 404 |\n| `assertApiTooManyRequests($response, $retryAfter)` | 429 + `Retry-After` |\n| `assertStructuredError($response, $code, $status)` | structured format |\n| `assertApiDataKey($response, $key, $value)` | `data.key` value |\n| `assertApiMeta($response, $key, $value)` | `meta.key` value |\n| `assertApiHasRequestId($response)` | `X-Request-ID` header |\n\n---\n\n## Configuration reference\n\nFull config is in `config/laravel-api.php`. Key sections:\n\n| Key | Default | Description |\n|---|---|---|\n| `openapi.enabled` | `true` | Enable OpenAPI generation |\n| `openapi.title` | app name | Spec title |\n| `openapi.version` | `1.0.0` | Spec version |\n| `openapi.default_path_prefix` | `/api` | Route prefix filter |\n| `openapi.cache.enabled` | `false` | Cache generated spec |\n| `openapi.docs_route.enabled` | `true` | Serve runtime JSON/YAML |\n| `openapi.docs_ui.enabled` | `false` | Enable Swagger/Redoc UI |\n| `response.error_format` | `envelope` | `envelope` or `structured` |\n| `response.envelope.*` | — | Configurable response keys |\n| `response.pagination.*` | — | OData-lite key names |\n| `request_id.enabled` | `true` | Attach correlation headers |\n| `request_id.header` | `X-Request-ID` | Request ID header name |\n| `versioning.enabled` | `false` | Validate `api-version` |\n| `versioning.supported` | `[]` | Whitelist (empty = accept all) |\n| `exceptions.auto_render` | `false` | Auto-register exception renderer |\n| `health.enabled` | `true` | Enable health endpoint |\n| `health.route` | `_health` | Health check URL path |\n\n---\n\n## Quality checks\n\nRun from the package directory:\n\n```bash\ncomposer test              # all tests\ncomposer test:unit\ncomposer test:integration\ncomposer analyse           # PHPStan level 5\ncomposer lint              # Pint style check\ncomposer release:check     # test + analyse + lint\n```\n\n---\n\n## Changelog and upgrade\n\n- Changelog: `CHANGELOG.md`\n- Upgrade notes: `UPGRADE.md`\n- Versioning policy: `docs/SEMVER_POLICY.md`\n\n## Project documents\n\n- `LICENSE` — MIT\n- `CONTRIBUTING.md`\n- `CODE_OF_CONDUCT.md`\n- `SECURITY.md`\n- `SUPPORT.md`\n\n\n## Features\n\n- Generate OpenAPI 3.0.3 specs from Laravel routes\n- Export JSON and YAML spec files\n- Serve live docs endpoints for JSON and YAML\n- Configurable metadata, server URL, and API path prefix\n- Action-based request and response mapping\n- Route/action operation overrides (summary, tags, security, and more)\n- Reusable `components.schemas` registry with provider support\n- Auto-inference from `JsonResource`/`ResourceCollection` return types\n- FormRequest validation rule inference for request schemas\n- Route filtering by name and middleware from CLI options\n- Optional static docs UI (Swagger UI or Redoc)\n- Unified API response helpers (success, failed, error, validation, and aliases)\n\n## Installation (local path repository)\n\n1. Add path repository in root `composer.json`:\n\n```json\n{\n  \"type\": \"path\",\n  \"url\": \"packages/yoosuf/laravel-api\",\n  \"options\": { \"symlink\": true }\n}\n```\n\n1. Require package:\n\n```bash\ncomposer require yoosuf/laravel-api:*\n```\n\n1. Publish config:\n\n```bash\nphp artisan vendor:publish --tag=laravel-api-config\n```\n\n1. (Optional) Publish docs UI assets:\n\n```bash\nphp artisan vendor:publish --tag=laravel-api-assets\n```\n\n## Commands\n\nGenerate both outputs to configured paths:\n\n```bash\nphp artisan api:openapi\n```\n\nGenerate only JSON:\n\n```bash\nphp artisan api:openapi --format=json\n```\n\nGenerate YAML to custom file:\n\n```bash\nphp artisan api:openapi --format=yaml --output=docs/openapi.v1.yaml\n```\n\nLimit generation to a prefix:\n\n```bash\nphp artisan api:openapi --prefix=/api/v1\n```\n\nGenerate with route filters:\n\n```bash\nphp artisan api:openapi --include-route=documents.store --exclude-route=documents.destroy --middleware=api\n```\n\n## Runtime endpoints\n\n- `GET /openapi.json`\n- `GET /openapi.yaml`\n\nOptional docs UI route:\n\n- `GET /api-docs`\n\nRoutes are configurable in `config/laravel-api.php`.\n\n## End-to-end quick start\n\n1. Install the package and publish the config:\n\n```bash\ncomposer require yoosuf/laravel-api:*\nphp artisan vendor:publish --tag=laravel-api-config\n```\n\n1. Enable the human-readable docs UI in `config/laravel-api.php`:\n\n```php\n'docs_ui' =\u003e [\n  'enabled' =\u003e true,\n  'driver' =\u003e 'swagger',\n  'route' =\u003e 'api-docs',\n  'title' =\u003e 'Laradoc API Reference',\n  'spec_url' =\u003e '/openapi.json',\n  'middleware' =\u003e [],\n],\n```\n\n1. Publish the UI assets:\n\n```bash\nphp artisan vendor:publish --tag=laravel-api-assets --force\n```\n\n1. Generate the OpenAPI artifacts:\n\n```bash\nphp artisan api:openapi --format=all --prefix=/api/v1\n```\n\n1. Open the machine-readable and human-readable endpoints:\n\n- `http://127.0.0.1:8000/openapi.json`\n- `http://127.0.0.1:8000/openapi.yaml`\n- `http://127.0.0.1:8000/api-docs`\n\nThe integration guide in `docs/PROJECT_INTEGRATION_GUIDE.md` demonstrates that full flow with real endpoints and payloads.\n\n## API response helpers\n\nUse the responder to avoid repeating JSON response structures in controllers.\n\nOptions:\n\n- Facade: `ApiResponse::responseSuccess(...)`\n- Helper: `response_success(...)`\n- Service: `app('laravel-api.response')-\u003esuccess(...)`\n- Trait: `Yoosuf\\\\LaravelApi\\\\Concerns\\\\HasApiResponses`\n\nExamples:\n\n```php\nreturn response_success(['user' =\u003e $user], 'Fetched');\nreturn response_failed('Validation failed', 422, ['email' =\u003e ['required']]);\nreturn response_error('Unexpected failure', 500);\n```\n\nAlias support (including user-requested typo compatibility):\n\n- `responseSuccess`\n- `responseFailed`\n- `responseError`\n- `responseErrror`\n\n## Quality and CI\n\nRun package quality checks from the package directory:\n\n```bash\ncomposer test\ncomposer test:unit\ncomposer test:integration\ncomposer analyse\ncomposer lint\n```\n\nGitHub Actions workflow is provided at `.github/workflows/laravel-api-quality.yml`.\n\n## Versioning policy\n\nThis package follows Semantic Versioning.\n\n- MAJOR: backward-incompatible API changes.\n- MINOR: backward-compatible feature additions.\n- PATCH: backward-compatible bug fixes.\n\nPublic API surface is defined in `docs/SEMVER_POLICY.md`.\n\n## Upgrade and changelog\n\n- Changelog: `CHANGELOG.md`\n- Upgrade notes: `UPGRADE.md`\n\n## Open source project documents\n\n- License: `LICENSE`\n- Contributing: `CONTRIBUTING.md`\n- Code of Conduct: `CODE_OF_CONDUCT.md`\n- Security Policy: `SECURITY.md`\n- Support Guide: `SUPPORT.md`\n- Detailed contributor workflow: `docs/CONTRIBUTING_GUIDELINES.md`\n\n## Documentation map\n\n- Architecture: `docs/ARCHITECTURE.md`\n- Configuration reference: `docs/CONFIG_REFERENCE.md`\n- Operations runbook: `docs/OPERATIONS_RUNBOOK.md`\n- End-to-end use cases: `docs/END_TO_END_USE_CASES.md`\n- SemVer and public API policy: `docs/SEMVER_POLICY.md`\n- Release process: `docs/RELEASE.md`\n- Future engineering pipeline: `docs/FUTURE_PIPELINE.md`\n- Contribution process: `docs/CONTRIBUTING_GUIDELINES.md`\n- Project integration guide: `docs/PROJECT_INTEGRATION_GUIDE.md`\n\n## Release and publishing\n\nBefore tagging a release, run:\n\n```bash\ncomposer release:check\n```\n\nFor monorepo-only usage, keep requiring via path repository.\nFor distribution, publish to Packagist using the process in `docs/RELEASE.md`.\n\n## Phase 2 configuration hooks\n\n- `openapi.providers`: class list for custom providers implementing:\n  - `Yoosuf\\\\LaravelApi\\\\OpenApi\\\\Contracts\\\\SchemaProvider`\n  - `Yoosuf\\\\LaravelApi\\\\OpenApi\\\\Contracts\\\\OperationOverrideProvider`\n- `openapi.action_map`: map by `Controller@method` to merge request/response schema fragments.\n- `openapi.overrides`: operation overrides grouped by `routes` and `actions`.\n- `openapi.components.schemas`: reusable component schemas.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoosuf%2Flaravel-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyoosuf%2Flaravel-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoosuf%2Flaravel-api/lists"}