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 Laravel Package

g4t/swagger

g4t/swagger is a Laravel package that generates Swagger/OpenAPI documentation from your routes and annotations. It automates API spec creation, keeps docs aligned with your code, and simplifies serving interactive documentation.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and publish

composer require g4t/swagger
php artisan vendor:publish --tag=swagger-config   # or --provider="G4T\Swagger\SwaggerServiceProvider"
php artisan vendor:publish --tag=swagger-assets   # swagger-ui assets, if the package ships them

If the tag names differ, run php artisan list | grep -i swagger and inspect vendor/g4t/swagger/src/ — this package is small enough to read end-to-end in ten minutes, and you should, because the surface API is not extensively documented.

Where to look first

  1. config/swagger.php (or g4t-swagger.php) — base path, output file, scan paths, UI route.
  2. vendor/g4t/swagger/src/Console/ — the generation command and its flags.
  3. vendor/g4t/swagger/src/routes/ — the docs route the package registers, and its middleware.
  4. The published swagger.json / api-docs.json — this is your source of truth when debugging, not the UI.

First use case

Document a single CRUD resource before touching anything else:

# 1. Point the scanner at one controller only
#    config: 'paths' => [app_path('Http/Controllers/Api/UserController.php')]

# 2. Generate
php artisan swagger:generate

# 3. Serve
#    visit the route the package registers (commonly /api/documentation)

Then open the generated JSON file directly and confirm the paths, parameters, and components.schemas blocks match what you expect. If the UI renders but the JSON is thin, you have an annotation/scanning problem, not a UI problem — always debug against the JSON.

Environment gating

Register/serve the docs route only outside production (or behind auth). The package usually reads a config flag; wrap it yourself if it doesn't:

// AppServiceProvider::boot()
if (! app()->isProduction()) {
    // route is auto-registered by the package; otherwise include its route file here
}

Implementation Patterns

1. Annotate at the controller, let the scanner fill the rest

The package's value proposition is deriving schemas from your code. In practice that means: annotate the request body and responses explicitly, and let route registration supply the path, method, and path parameters. Anything relying on inference from bare array return types will come out as an empty object.

/**
 * @OA\Post(
 *   path="/api/users",
 *   tags={"Users"},
 *   @OA\RequestBody(required=true, @OA\JsonContent(ref="#/components/schemas/UserRequest")),
 *   @OA\Response(response=201, description="Created", @OA\JsonContent(ref="#/components/schemas/UserResource"))
 * )
 */
public function store(StoreUserRequest $request): UserResource

2. Drive schemas from FormRequests and API Resources

The highest-leverage habit: one components.schemas entry per FormRequest (input) and per JsonResource (output), reused via $ref. This keeps validation rules and docs from drifting, because both live next to each other. Where the package can infer rules() it will; where it can't (Rule::unique, closures, Rule::in), hand-write the property.

3. Split generation by API surface

For multi-version or multi-module APIs, run the generator once per directory into separate files rather than one monster document:

// config: 'paths' => [app_path('Http/Controllers/Api/V1')], 'output' => 'public/docs/v1.json'
// then a second entry for V2 with its own output

Then serve each with its own UI mount or a small swagger-ui config selecting the file. This avoids components.schemas name collisions between versions — the most common breakage in versioned APIs.

4. Generate in CI, serve statically

Treat the spec as a build artifact:

# deploy step
- php artisan swagger:generate
- test -s public/docs/api.json   # fail the build if generation broke

Committing the JSON to the repo gives you diffable API contract changes in PRs, which is the single best reason to use a package like this. Dynamic generation on every request is fine locally but wasteful in production.

5. Protect the docs route

If the UI route is auto-registered, wrap it with the app's auth middleware (or an IP allowlist) in config / the service provider. Publicly exposed Swagger UIs are a routine finding in API pentests, and this package does not decide that for you.

6. Use it as a starting point, not a contract

The realistic workflow: generate once, then hand-edit / annotate the 20% of endpoints the scanner gets wrong. The scanner gets you 70% cheaply; treat the remaining 30% as annotation work you would have done anyway with zircote/swagger-php.

Gotchas and Tips

Auto-scanning blind spots

  • Closure routes, invokable controllers without typed __invoke returns, and Route::resource expansions often produce skeletal or missing paths. Verify route count in the JSON against php artisan route:list --path=api.
  • Controllers outside app/Http/Controllers (modular/Domain layouts) are silently skipped unless you add the path in config.
  • Return types of JsonResponse, Response, or mixed yield empty schemas — annotate them explicitly.

Route caching php artisan route:cache will freeze the package's docs route registration and any config-driven route logic. Clear and re-cache after changing swagger config; in CI always route:clear before swagger:generate.

Stale output The most common "bug report" is simply old JSON. If the UI shows an endpoint you deleted, you didn't regenerate. Add generation to the deploy pipeline rather than relying on developers to remember.

Type inference failures

  • Untyped $request->all() payloads → empty properties.
  • Nullable unions (?string) sometimes emit type: string without nullable: true; check and correct.
  • Enum casts on models are usually documented as plain string — add the enum list by hand.

Config quirks

  • Paths in config are typically resolved relative to the app root; absolute paths from app_path() are safest.
  • If both a config file and a provider-level override exist, the provider usually wins — check vendor/ before concluding the config is ignored.
  • The UI's "try it out" needs the correct servers/host + basePath; a mismatch here makes working endpoints look broken in the browser and sends people debugging the wrong layer.

Debugging checklist

  1. cat public/docs/*.json | jq '.paths | keys' — are your routes present?
  2. jq '.components.schemas | keys' — did schemas generate?
  3. Run the generation command with -v (or equivalent) to surface scanner parse errors — a single malformed docblock can abort scanning for that file silently.
  4. Validate the output against the OpenAPI spec (e.g. npx @redocly/cli lint) before blaming the package for UI rendering issues.

Extension points

  • The generator is a thin wrapper over zircote/swagger-php in most builds; if you need behavior it lacks, subclass or re-invoke the underlying scanner directly rather than forking the package.
  • Add custom components.schemas via a dedicated annotations file included in the scan paths — this is the cleanest way to document shared DTOs and error envelopes (ErrorResponse, pagination wrappers) that no controller owns.

Maintenance risk — read this before committing 124 stars, zero dependents, and a single-maintainer bus factor mean you should: pin an exact version in composer.json, commit composer.lock, and be prepared to swap to darkaonline/l5-swagger + hand-written annotations if the package goes quiet. The annotations you write are portable; the generator wrapper is not. Keeping the annotated portion of your spec package-agnostic is cheap insurance and the main architectural decision to make on day one.

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.
alphabalex/messaging-made-easy
rawphp/warp
shootkiran/merobug
narakode/fineauth
numencode/wn-syncops-plugin
ibnnajjaar/mib-global-pay
ably/pubsub-server
mstfkhazaal/defender
mfonte/base62x
karnoweb/metapilot
tobya/bcsapiwrapper
swalker2/cpanel
vish4395/laravel-translation-manager
morningtrain/economic
teksite/systeminfo-laravel
atomcms/voting
run6/weather
siokas/laravelembeddirectives
adamlien/pkuuids
gilsonsouza/lara-doc-generator