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

Idoc Laravel Package

ovac/idoc

IDoc is a Laravel package that generates API documentation from your routes and controller annotations. It provides a clean, searchable interface with minimal setup, helping keep your API reference accurate and in sync with your codebase.

View on GitHub
Deep Wiki
Context7

Getting Started

Install it as a dev dependency so it never ships to production:

composer require ovac/idoc --dev
php artisan vendor:publish --provider="Ovac\Idoc\IdocServiceProvider"

That publishing step is where the real work starts — open config/idoc.php before running anything. The three keys that matter on day one are the models/source path it should scan, the output path for the generated artifacts (the interactive HTML and the OpenAPI 3.0 JSON/YAML), and the app metadata (title, version, description, servers). Get those right and the first run is useful; get them wrong and you'll spend an hour wondering why half your API is missing.

Then generate:

php artisan idoc:generate

You should get two things: a browsable HTML doc and a spec file you can feed to Swagger UI, Redoc, Postman, or Insomnia. Look at the JSON first, not the HTML. The HTML hides omissions; the raw spec exposes them immediately (missing paths, empty properties, "type": "string" on everything).

First use case worth doing: pick one resource — say Post with index/show/store/update/destroy — annotate or configure it, regenerate, and diff the spec against what the endpoint actually returns. That single loop teaches you 80% of how the package thinks, and it's the loop you'll repeat for every other resource.

Implementation Patterns

Model-first, then controller. The package derives request/response shapes primarily from your Eloquent models (columns, casts, $fillable, $hidden) and from your route definitions. The most reliable workflow is: make the model honest first (correct casts, correct $hidden, real column types from migrations), then layer request validation rules on top. If published_at is cast to datetime you get string + format: date-time; if it's an untyped attribute you get mush.

Treat validation rules as the request-body source of truth. FormRequest rules are the highest-signal input you can give the generator:

public function rules(): array
{
    return [
        'title'       => ['required', 'string', 'max:180'],
        'body'        => ['required', 'string'],
        'status'      => ['required', Rule::in(['draft', 'published'])],
        'published_at'=> ['nullable', 'date'],
        'tags'        => ['array'],
        'tags.*'      => ['integer', 'exists:tags,id'],
    ];
}

Anything statically readable (strings, arrays, in: lists) converts cleanly. Closures and custom Rule objects do not — see Gotchas.

Generate in CI, commit the spec, gate the PR. The pattern that ages best:

- run: php artisan idoc:generate
- run: npx @redocly/cli lint storage/app/idoc/openapi.json
- run: git diff --exit-code storage/app/idoc/  # fail if docs drifted

This turns "someone forgot to update the docs" into a red build. It's the single highest-value habit with any spec generator.

Serve docs in-app, but only behind a gate. Expose the generated HTML on a dev-only route (or local env check) rather than a public /docs. If you need it in staging, wrap it in auth + a feature flag. Docs leak endpoint topology, field names, and sometimes example payloads with real-looking data.

Customize through published views/templates, not by editing output. If the default HTML template doesn't fit your product, publish the views and edit those; regeneration then overwrites the output without overwriting your customizations. Same principle for any per-entity description or grouping: put it in config/annotations, not in the generated file.

Use tags/grouping deliberately. Group by domain (Billing, Catalog, Auth) rather than by controller name. It's cheap now and makes the generated HTML navigable at 60+ endpoints. Pair with servers per environment so the "Try it" panel actually hits something.

Versioned docs = separate output paths. If you ship /api/v1 and /api/v2, generate twice into distinct output directories with distinct info.version values rather than trying to merge.

Import into Postman as a smoke test. A generated OpenAPI file is an instant collection. Run it against a seeded local DB after generation to catch specs that are syntactically valid but semantically wrong (wrong status codes, missing required fields).

Gotchas and Tips

  • It only knows what you typed. Untyped controller params, $request->all(), and mixed returns produce empty schemas. The fix is always the same: type-hint the request class, return a Resource/JsonResource, or add an explicit override. Budget time for this; it's not a bug.
  • Custom validation rules silently degrade. Rule::in([...]) usually works; new UniqueEmailRule() or a closure inside rules() yields a naked string. Replace with in: syntax where possible, or annotate manually.
  • DB connection at generation time. Schema-introspecting generators need a live database. In CI, point at a throwaway SQLite/MySQL instance and run migrations before idoc:generate, or your columns will be missing or stale.
  • Stale caches bite hard. After changing config or source paths: php artisan config:clear && php artisan route:clear. If routes were cached when you generated, endpoints may be absent entirely — this is the #1 "why is my new route not in the docs" cause.
  • Don't hand-edit the generated spec. It will be overwritten and your changes will vanish, usually the day before a release. Put every manual adjustment in config, annotations, or a published template. If there's genuinely no hook, wrap the generator in a small post-processing command that patches the JSON deterministically.
  • Watch the casts. Enums (PHP 8.1 backed enums), Carbon mutators, array/json casts, and accessors often resolve to string or object with no detail. If a field is an enum, list the values explicitly — consumers use that for codegen.
  • Relationships and pagination wrappers. Nested JsonResource output (data: [...] + meta/links) is rarely inferred correctly. Either document the envelope in config or add it to a response schema manually; otherwise every "Try it" response looks like a bug to a frontend dev.
  • File uploads need multipart/form-data, which many generators default to JSON. If an endpoint takes a file, verify the content type in the raw spec, not the rendered page.
  • OpenAPI 3.0 ≠ 3.1. The output targets 3.0. Some modern tooling (certain Redoc versions, some SDK generators) assumes 3.1 semantics around null types. Test your actual consumer before committing to a doc pipeline.
  • Debugging order of operations: (1) raw JSON, (2) routes present? (3) schemas populated? (4) content types right? (5) only then look at the HTML. Nine times out of ten the problem is at step 2 or 3.
  • Extension point to remember: the config's model/source paths and any per-model overrides are your escape hatch when reflection fails. Get comfortable writing overrides for the 10% of endpoints the generator can't infer — that's a normal, healthy ratio, not a failure of the tool.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
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
cgv/localized-resource