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

nextapps/laravel-swagger-ui

Nextapps Laravel Swagger UI lets you browse and test your OpenAPI/Swagger documentation directly inside a Laravel application. It serves the Swagger UI interface with configurable options, requiring minimal setup and no separate documentation server.

View on GitHub
Deep Wiki
Context7

Getting Started

Three commands and a JSON file get you interactive API docs:

composer require nextapps/laravel-swagger-ui
php artisan vendor:publish --provider="NextApps\SwaggerUi\SwaggerUiServiceProvider"

Then drop your OpenAPI document where the published config points (by default the package expects a spec in public/, e.g. public/swagger.json or public/docs/swagger.json) and visit the docs route — typically /api/documentation.

Where to look first:

  1. config/swagger-ui.php (or similarly named file after publishing) — this is the whole surface area. You'll find the route/prefix, the spec file path or URL, the view to render, middleware, and any asset-source toggle.
  2. routes/ in the package vendor directory — confirm the exact URI your version registers, since it's easy to guess wrong.
  3. The published Blade view — the Swagger UI bootstrap config (url:, dom_id, deepLinking) lives there, and it's the main override point.
  4. The published public assets — Swagger UI's CSS/JS plus an oauth2-redirect.html shim. That redirect page is what Swagger UI's OAuth2 Authorization Code flow posts back through, so it only matters to you if your spec declares an oauth2 security scheme.

First real use case: you have a Laravel JSON API, a hand-maintained or CI-generated openapi.json, and no appetite for the annotation toolchain that l5-swagger drags in. This package is the thin "serve the UI, point it at a file" layer. It does not generate specs — that's a deliberate boundary, and understanding it early saves you from expecting annotation scanning that isn't there.

A sensible first commit: publish the config, commit the spec to public/docs/openapi.json, gate the route to local and staging only, and link to it from your team README.

Implementation Patterns

Bring your own spec generator. The package renders; it doesn't describe. Pair it with whatever produces the file:

  • dedoc/scramble — generates OpenAPI from your routes/FormRequests with zero annotations. Best fit for most Laravel apps.
  • knuckleswtf/scribe — if you already have Scribe postman/HTML output, emit the OpenAPI variant and point this UI at it.
  • Hand-written YAML/JSON — fine for small or contract-first APIs.

The integration pattern is a CI step or an artisan command that writes the spec into public/, then the package serves it statically. Nothing else in your app needs to know about the docs.

Environment-gated route registration. The cleanest production story is not "protect the docs route" but "don't register it at all." Wrap the service provider's route registration or set the config's enabled/route middleware so /api/documentation simply 404s in production:

// config/swagger-ui.php
'route' => [
    'enabled' => env('APP_ENV') !== 'production',
],

If you do want docs in production (useful for partner-facing APIs), gate with auth + a policy that only staff pass, e.g. 'middleware' => ['web', 'auth', 'can:viewApiDocs']. Basic auth via a web middleware alias is a common lighter-weight choice.

Versioned specs. There is no first-class multi-spec support, so pick one:

  • Two config keys / two route registrations (duplicate the block per version), or
  • One UI with Swagger UI's spec-selector — achievable by overriding the published view to pass a urls: [{name, url}, ...] array instead of a single url, which Swagger UI supports natively. This is the pragmatic route and costs ~10 lines of Blade.
  • Separate hosts/prefixes per major version if your API is genuinely split.

Proxy the spec through a route when it's private. If the spec lives in storage/app/ rather than public/ (so you can gate it), add a tiny controller route that returns the file with Content-Type: application/json and point the config's spec URL at that route. This keeps the spec out of the public webroot while still letting Swagger UI fetch it.

OAuth2 in the UI. If your spec declares an authorizationCode flow, Swagger UI opens a popup and lands on the package's oauth2-redirect.html. Two things to wire up: point the spec (or the view's bootstrap config) at the absolute published URL of that redirect page — oauth2RedirectUrl: '{{ asset("vendor/swagger-ui/oauth2-redirect.html") }}' — and have the redirect page reachable without session/auth middleware of its own, otherwise the popup hangs. Keep the redirect asset in your publish step so upgrades can't leave you with a stale copy.

Deployment checklist item, in your Dockerfile or deploy script:

php artisan vendor:publish --provider="NextApps\SwaggerUi\SwaggerUiServiceProvider" --tag=swagger-ui-assets --force
php artisan config:cache

Publishing assets at image build time (rather than relying on php artisan serve's dev behaviour) avoids the blank-page class of bugs entirely — and it's also what keeps oauth2-redirect.html in sync with the Swagger UI JS version it references.

Override the view, not the vendor files. Publish views and edit resources/views/vendor/swagger-ui/*.blade.php. That's your extension point for persistAuthorization, docExpansion, request interceptors, custom CSS, or injecting a company logo.

Gotchas and Tips

"Failed to load API definition" is almost always a path problem, not a UI problem. The browser fetches the spec relative to the page URL, so /api/documentation looking for swagger.json resolves to /swagger.json, not /api/swagger.json. Fix by using an absolute URL in the config/view (url: '{{ url("/docs/openapi.json") }}') rather than a bare filename. Open devtools Network tab before touching anything else.

config:cache will silently ignore your edits. Classic Laravel footgun, but it bites this package hard because the route prefix, middleware, and enabled flag all live in config. If changes to config/swagger-ui.php "do nothing," run php artisan config:clear.

Blank page or unstyled UI means unpublished assets. The view references CSS/JS the package publishes; if vendor:publish wasn't run (or was run before an upgrade that changed asset names), you get 404s on the static files. Re-publish with --force after every package bump and hard-refresh — browser caches on hashed-name assets are sticky.

OAuth2 popups that never close are an asset problem, not an auth problem. The redirect page is a static HTML file with a hard-coded reference to Swagger UI's JS. If that reference is stale (a published-asset mismatch after an upgrade) or the page 404s because assets weren't re-published, the popup completes the provider handshake but never posts the token back to the UI, so Authorize silently fails. Version 2.1.1 fixed exactly this: a wrong javascript file reference in the redirect HTML. If you run OAuth2 flows, don't pin below 2.1.1, and after any bump open the redirect URL directly in a browser and confirm the script tag points at a file that returns 200.

Behind a load balancer, asset URLs can come out as http:// or the internal hostname. This is the asset() helper reading the wrong scheme/host. Configure TrustProxies properly; the symptom is a docs page that loads but with mixed-content or unreachable assets — and OAuth2 redirects failing because the provider bounces to an http:// URL.

Same-origin applies to the spec. Swagger UI's fetch of your JSON is a normal browser request. If you host the spec on S3 or a separate docs domain, you need CORS or you'll see a CORS error rather than a 404 — easy to misdiagnose as a path issue.

YAML is usually fine but check the content type. Swagger UI auto-detects, but a YAML file served as text/plain from nginx can fail to parse. Serving JSON removes the whole class of problem; if you must use YAML, verify the served Content-Type and that indentation survived any CI templating step.

Keep the version pinned and read the changelog on bumps. 281 stars and near-zero dependents means the package is a thin wrapper with a small maintenance surface — good for stability, but there's no ecosystem of people hitting the same upgrade bugs. Pin to a minor version in composer.json and smoke-test the docs route after upgrades; the risk is asset path/layout churn (as 2.1.1 shows on the OAuth2 redirect page), not API breakage.

Know when to switch. If you find yourself wanting annotation scanning, per-route doc generation, or generated request examples, you want l5-swagger or Scramble's own UI. This packages shines precisely because it does one thing; the moment you're overriding the view heavily to add features, you're paying maintenance cost for something a fuller package already ships.

Quick debugging order of operations: (1) php artisan route:list | grep -i swagger to confirm the route exists and see its middleware; (2) curl the spec URL directly; (3) check the rendered HTML source for the url: value Swagger UI received; (4) devtools Network — and for OAuth2, open oauth2-redirect.html directly and check its script tag resolves. This sequence resolves roughly every issue you'll hit.

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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
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