noitran/opendox
OpenDox is a Laravel package for generating OpenAPI/Swagger documentation for your API. It helps keep endpoint specs close to your application code, making API documentation easier to maintain, share, test, and use during client integration. Supports Laravel conventions and common API workflows.
Install via Composer
composer require noitran/opendox
Laravel 5.5+ auto-discovers Noitran\OpenDox\Providers\OpenDoxServiceProvider. For Lumen, register it manually in bootstrap/app.php:
$app->register(\Noitran\OpenDox\Providers\OpenDoxServiceProvider::class);
Publish the config (Laravel):
php artisan vendor:publish --tag=opendox
Lumen users should copy the config into config/opendox.php themselves and call $app->configure('opendox'); before the provider registration.
Point the package at your annotated code. Open config/opendox.php and set the paths/globs the swagger-php scanner should crawl (typically your app/Http/Controllers and any app/OpenApi schema files). Set the title, version, servers, and the output path for the generated JSON.
Add your first annotation to a controller:
/**
* @OA\Get(
* path="/api/users",
* tags={"Users"},
* @OA\Response(response=200, description="OK")
* )
*/
public function index() { ... }
View the docs. The package ships two UIs — hit the Redoc route (usually /opendox/redoc) for a clean read-only reference, or the SwaggerUI route (/opendox/swagger) to try requests in the browser. First use case: annotate one controller, load SwaggerUI, confirm the endpoint appears, then expand coverage controller by controller.
@OA\* blocks next to the methods they describe. It is the fastest way to keep docs in sync because reviewers see doc changes in the same diff as the code change.@OA\Schema on dedicated classes (e.g. app/OpenApi/Schemas/User.php) instead of stuffing them into controllers. This keeps controllers readable and lets you $ref schemas from many endpoints.Users, Orders, V1/Users) — SwaggerUI renders a section per tag, which is essential once you cross ~20 endpoints.@OA\SecurityScheme on a single "root" annotation class (e.g. @OA\Info + @OA\Server + @OA\SecurityScheme in one file), then reference the scheme from endpoints. Don't redeclare per controller.servers entry so "Try it out" hits the right host.Controllers/Api, one scanning Controllers/Admin — exposed at different route prefixes. Useful when you don't want internal endpoints leaking into a public reference.git diff on the generated file is a cheap, effective gate.zircote/swagger-php major version will fight modern PHP/Laravel. Pin swagger-php in composer.json and expect to hold back swagger-php upgrades. If you're starting greenfield in 2024+, seriously weigh dropping straight to swagger-php + a static Redoc page instead.config/opendox.php, run php artisan config:clear. Stale cached config is the #1 cause of "my endpoint disappeared."@OA\* block usually just omits that operation rather than erroring. If an endpoint is missing, re-read the block for a missing closing paren/brace — swagger-php's error output is easy to miss and often buried in logs.storage_path() under app/ is a safe target in Laravel.->group() with a prefix that shadows /opendox/*, the UIs 404 while the JSON endpoint still works. Check php artisan route:list (Laravel) or $app->getRoutes() (Lumen).servers must be absolute. A relative or empty servers[].url breaks "Try it out" in SwaggerUI — it defaults to the current origin, which is usually wrong when docs are hosted separately from the API. Set the base URL explicitly per environment.type: ["string", "null"] union types or other 3.1 constructs — they'll be ignored. Use nullable: true./opendox/* routes behind your standard auth guard (or disable them entirely in prod and serve the static JSON from a docs subdomain) — a live SwaggerUI in production is an accidental "try destructive endpoints" playground.How can I help you explore Laravel packages today?