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

Swagger Lume Laravel Package

darkaonline/swagger-lume

SwaggerLume brings Swagger/OpenAPI documentation to Laravel and Lumen apps. It wraps swagger-php to scan your annotations and generate interactive API docs, with a bundled Swagger UI and simple configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

SwaggerLume is a thin Lumen wrapper around zircote/swagger-php: it wires annotation scanning, a generate command, and a bundled Swagger UI route into your Lumen app. You own the annotations; the package owns the plumbing. Release 11.0 lines the wrapper up with Lumen 11 and swagger-php 4 — if you're on Lumen 10 or swagger-php 3, stay on the 10.x line.

Minimal path from zero to a rendered spec:

composer require darkaonline/swagger-lume
php artisan swagger-lume:publish   # config/swagger-lume.php, views, UI assets
php artisan swagger-lume:generate  # writes storage/api-docs/api-docs.json

Register the provider in bootstrap/app.php (or app.php on newer Lumen), and enable facades — the docs controller and UI rendering rely on them:

$app->withFacades();
$app->register(DarkaOnLine\SwaggerLume\SwaggerLumeServiceProvider::class);
// if config() values come back null:
// $app->configure('swagger-lume');

Where to look first:

  1. config/swagger-lume.php — this is the whole integration surface: paths.annotations (what gets scanned, defaults to base_path('app')), paths.docs (output dir), routes.* (the /api/documentation UI and /docs JSON endpoints), scanOptions, constants, generate_always.
  2. storage/api-docs/api-docs.json — the artifact you actually ship, diff, and lint. Treat it as a build output with a review step.
  3. Your controllers — annotations live in docblocks (or PHP attributes on swagger-php 4) inside any scanned file.

First use case: annotate exactly one endpoint end-to-end before touching anything else. Put a single required @OA\Info in one file (a dedicated app/OpenApi/Info.php works well), add @OA\Get above one controller method with a @OA\Response, run swagger-lume:generate, and open /api/documentation. Import the annotation namespace at the top of every annotated file — without it, docblock annotations are not resolved:

use OpenApi\Annotations as OA;   // required for @OA\* docblock annotations

Getting one operation rendering correctly tells you scanning, the generator, the route, and the assets are all wired. Everything after that is repetition.

Implementation Patterns

Single source of truth for the root document. Keep @OA\Info, @OA\Server, and global @OA\SecurityScheme in one dedicated class (e.g. app/OpenApi/OpenApi.php). swagger-php errors hard if it finds two Info blocks, so centralising the header avoids a class of merge failures.

Environment-aware servers via constants. The config constants block define()s PHP constants at boot; reference them directly in annotations instead of hardcoding hosts:

// config/swagger-lume.php
'constants' => ['L5_SWAGGER_CONST_HOST' => env('L5_SWAGGER_CONST_HOST', 'http://localhost:8000')],
/**
 * @OA\Server(url=L5_SWAGGER_CONST_HOST, description="Current environment")
 */

This is the standard way to get one spec that points at staging in CI and localhost in dev without editing annotation files.

Schemas as classes, not inline. Define @OA\Schema on DTOs / resources / models (or a app/OpenApi/Schemas folder added to paths.annotations), then $ref from operations:

/**
 * @OA\Schema(schema="User", required={"id","email"})
 */
class UserSchema {
    /** @OA\Property(type="integer", example=1) */
    public $id;
}
'@OA\JsonContent(ref="#/components/schemas/User")'

Use allOf to compose pagination envelopes (PaginatedUsers = allOf[UserList, Pagination]) rather than repeating fields per endpoint. This is where the day-to-day maintenance cost lives — the more $ref, the less drift.

Attributes over docblocks if your PHP allows it. swagger-php 4 — which 11.0 binds to — reads #[OA\Get(...)] attributes natively. They don't need docblock parsing, survive IDE refactors better, and read as code rather than comments — worth adopting for new endpoints even if legacy controllers stay on annotations. Note the import differs: attributes need use OpenApi\Attributes as OA;.

Dev vs. prod generation. In local development set SWAGGER_GENERATE_ALWAYS=true (or generate_always in config) so the JSON regenerates on each request and you never see stale docs. In production do the opposite: generate at build/deploy time (composer script or deploy hook), commit or artifact-store the JSON, and leave generate_always off — it writes to disk on every request and can leak internal route structure if the docs route is exposed.

Protect the docs route with middleware, not hope. The UI and JSON routes are registered by the provider. Use routes.middleware.docs (and routes.middleware.api) in config to apply Lumen middleware — auth in production, nothing in local. Alternatively disable the routes entirely outside non-prod and serve the static JSON from a docs site.

Validate and diff in CI. The package generates; it does not validate. Add a CI step that runs swagger-lume:generate then lints the output (spectral, swagger-cli validate, or Redocly), and commit api-docs.json so PR diffs show the contract change. An undocumented breaking change becomes visible in review instead of in a client's bug report.

Reuse across the app. For multi-module Lumen apps, point paths.annotations at an array of directories (e.g. app/Http/Controllers, app/OpenApi, app/Modules/*/Http) and use scanOptions.exclude to skip vendor-ish or generated code. Keep one annotation namespace convention so reviewers know where to look.

Gotchas and Tips

  • Required @OA\Info() not found is the first error nearly everyone hits. It means the scanned paths contain no Info block — either you haven't written one, or it lives outside paths.annotations, or you forgot to regenerate.
  • Missing use OpenApi\Annotations as OA; silently erases annotations. Docblock annotations are resolved through the imported namespace; without the use statement the @OA\* tags in that file are skipped with no error, and the operation just doesn't appear. (11.0's docs PR calls this out explicitly — it's the most common "my annotation does nothing" cause.)
  • Annotations are only read from scanned paths. A controller outside paths.annotations is silently absent from the spec. No warning, just a missing endpoint. When an operation vanishes, check the path config before debugging the annotation.
  • Undefined constants in annotations throw in PHP 8+. If L5_SWAGGER_CONST_HOST isn't defined (because config didn't load, or you removed the constants entry), the annotation evaluation fails rather than falling back to a literal. Always give the constants entry a default value.
  • Blank page or 500 on /api/documentation almost always means the Lumen bootstrap is incomplete: facades not enabled, views/assets not published, or swagger-lume:publish run before the provider was registered. Run publish again after registering and confirm the UI asset files exist.
  • Duplicate schema names merge unpredictably. Two @OA\Schema(schema="User") blocks in different files don't error cleanly — they merge properties. Prefix schemas per module (AdminUser, PublicUser) or keep a single registry.
  • Version alignment is a three-way match. 11.0 targets Lumen 11 + swagger-php 4; 10.x targets Lumen 10 + swagger-php 3. Upgrading Lumen without bumping the wrapper (or the reverse) produces confusing generator errors that look like annotation bugs. Check composer.json constraints for zircote/swagger-php before any framework upgrade, and expect to migrate @OA docblocks wholesale if you jump swagger-php majors.
  • proxy and additional_config_url exist for a reason. Behind a load balancer or on a subpath, the UI's fetch of the JSON fails with a CORS/404 mix. Set proxy to the external base URL, or point additional_config_url at a reachable spec.
  • The JSON route is separate from the UI route (routes.docs vs. routes.api). If the UI loads but shows "fetch failed", the JSON endpoint is blocked by middleware or the wrong prefix, not the assets.
  • Don't generate in a request path in production. Beyond the write cost, generate_always can expose endpoints you deliberately don't document. Gate it to APP_ENV !== 'production'.
  • Extension point when the wrapper lags: it's a small package, and its whole job is calling swagger-php's Generator. If a Lumen release outpaces the wrapper — historically the norm, since 11.0 landed well after Lumen 11 shipped — you can invoke \OpenApi\Generator::scan([...]) directly in a custom artisan command and keep using the published UI assets. The annotations themselves are portable.
  • Maintenance risk is low but real: a few hundred stars, MIT, a small maintainer surface, and the heavy lifting lives in swagger-php. Budget for the wrapper going quiet between Lumen majors; your annotations, not the package, are the durable asset.
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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast