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

Laravel Swagger Ui Laravel Package

wotz/laravel-swagger-ui

Laravel Swagger UI exposes your OpenAPI v3 JSON or YAML file through a built-in Swagger UI at /swagger, automatically using the current environment’s base URL. Install via Composer, publish the config, and customize paths, versions, access gates, and OAuth2 settings.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require wotz/laravel-swagger-ui
php artisan swagger-ui:install

The install command publishes two things you should open immediately:

  1. config/swagger-ui.php — the only file you'll touch 95% of the time. It controls the route path (default swagger), the spec file locations, server URL rewriting, OAuth prefill, middleware, CSS, page title, validator URL and MCP.
  2. app/Providers/SwaggerUiServiceProvider.php — contains the gate() method that decides who can see the UI outside the local environment.

Then drop your spec in the default location:

resources/swagger/openapi.json   # or .yaml / .yml

and visit /swagger. In local that's it — no gate, no auth, no extra routes to write.

Check the generated provider is actually bootstrapped: on Laravel 11+ that means it appears in bootstrap/providers.php (older apps: config/app.php). If swagger-ui:install was run on an older skeleton, verify it manually, because a missing provider silently means an unregistered gate.

Your first real use case: keep the spec next to the code it describes, and use Swagger UI's Try it out against your local API while you build endpoints. Because the package rewrites the spec's servers entry to the current app URL, you can click through endpoints without editing the spec between environments.

Implementation Patterns

Spec as a committed artefact. Treat resources/swagger/openapi.json like a migration: versioned in git, reviewed in PRs, regenerated by whatever generator you use (annotations, Scramble, Scribe export, hand-written). Point versions at that file rather than a URL so the docs ship with the code that implements them.

Multiple versions as separate routes. The versions array is keyed, and each key becomes its own Swagger UI route:

'path' => 'swagger',
'versions' => [
    'v1' => resource_path('swagger/v1.json'),
    'v2' => resource_path('swagger/v2.json'),
],

That gives /swagger/v1 and /swagger/v2. Use this instead of swapping files, so consumers on the old contract keep working docs while you build the new one.

External specs. A version value can be a URL instead of a path, which is useful when the spec lives in another repo or a docs service. Combine it deliberately with modify_file (below) — rewriting a remote spec is often wrong.

Environment-aware URLs. With modify_file enabled (default) the package rewrites servers[].url and the OAuth URLs to the active base URL at render time. The file on disk is untouched. This is what makes one spec usable across local, staging and prod without templating.

For multi-tenant or localized APIs, use server_url with placeholders plus server_variables:

'server_url' => 'https://api.example.com/{Language}/v1',
'server_variables' => ['Language' => ['default' => 'en']],

The {Language} key must match the array key exactly, case included.

Gate patterns that scale. Default-deny outside local:

Gate::define('viewSwaggerUI', fn ($user = null) => $user !== null && (
    $user->hasRole('developer') || $user->can('view-api-docs')
));

If your app already has SSO, prefer putting the existing auth middleware in the package's middleware config and keeping the gate as a coarse "is this person allowed at all" check. The gate is also the same gate that protects the MCP server, so decide once.

OAuth2 prefill for internal APIs. Configure oauth.token_path, refresh_path, authorization_path and the client credentials from env. This turns Swagger UI into a working test console for a Passport-protected API without every developer pasting a token. For authorization-code flows, the package ships the OAuth2 redirect handler (added in 0.10.0), so the redirect URI must be registered on your OAuth client.

MCP for agent/LLM tooling. Enable mcp.enabled after installing laravel/mcp. The MCP server exposes information about your specs, guarded by auth:api and the viewSwaggerUI gate. On Passport you must additionally call Mcp::oauthRoutes() and supply a Passport authorization view. This is a niche but genuinely useful pattern: one spec file, human docs and machine-readable tool definitions from the same source.

CI guardrail. Validate the spec in CI (spectral or swagger-cli validate) rather than discovering a broken file by loading the UI. A malformed spec usually renders as an empty or half-broken page, not a clear exception.

Gotchas and Tips

"It 404s / 403s on staging." By default the UI is local-only. The gate in SwaggerUiServiceProvider is the fix, not the config file. This is by far the most common first-day problem.

modify_file surprises. Rewriting is done at request time. If your spec legitimately serves multiple hosts, or points at a CDN/remote spec, set modify_file => false and hardcode servers in the spec. Symptom of a bad rewrite: correct spec file, wrong base URL in the UI's server dropdown.

Use OpenAPI v3 only. Swagger 2.0 files will not render properly. Check the openapi: header before debugging anything else.

YAML failures are quiet. Parse errors tend to surface as a blank UI rather than a stack trace. Validate the YAML locally first, then check storage/logs/laravel.log.

Config and route caching. After editing config/swagger-ui.php, run php artisan config:clear (or re-run config:cache). Route changes from path or new versions keys need route:clear if you've cached routes. Browser-side, hard-refresh — the UI and its assets are cached aggressively.

Version keys are URLs. Renaming v1 to 1.0 breaks every bookmark and any link in your onboarding docs. Pick stable keys early.

CORS applies to Try it out. Requests fire from the browser, so if the API is on another origin you still need CORS headers on the API — the URL rewrite does not solve that.

Keep the OAuth secret out of git. Use SWAGGER_UI_OAUTH_CLIENT_SECRET from env, and consider whether a confidential client secret belongs in a browser-served page at all in production. Prefer a public client with PKCE where your flow allows it.

Upgrade path. The namespace changed from NextApps to Wotz in 1.0.0, and 2.0.0 dropped PHP 8.1/8.2 and Laravel 9/10 while adding the MCP server. On any major bump, delete and re-publish the config and the service provider, then re-apply your gate and config edits — otherwise you'll be running a stale published provider against new package internals.

Extension points, in order of usefulness: the gate, the middleware array (put it behind your existing auth), the CSS option and page title for embedding in an internal portal, the validator URL to disable the external validator on air-gapped networks, and finally publishing/vendoring the view if you need structural changes to the page itself.

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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo