Generate Laravel OpenAPI Documentation Automatically

Generate Laravel OpenAPI Documentation Automatically

Published · Updated

Generate accurate OpenAPI documentation automatically from your Laravel application with Scramble. No hand-maintained PHPDoc annotations required.

Maintaining API documentation by hand creates a second version of your API: one in the application code and another in an OpenAPI file or a set of PHPDoc annotations. Eventually, the two drift apart.

Scramble takes a different approach. It automatically analyzes your Laravel routes and application code to generate an OpenAPI 3.1 document, often called Swagger documentation. Validation rules become request schemas, API resources become response schemas, and the generated documentation stays aligned with the code.

Install Scramble and generate the documentation

Install Scramble in your Laravel application:

composer require dedoc/scramble

That is enough to get started. Scramble registers two routes:

  • /docs/api renders interactive API documentation.
  • /docs/api.json returns the generated OpenAPI document.

By default, Scramble documents routes whose URI starts with api. Open /docs/api and you should already see your endpoints. You do not need PHPDoc annotations or a separate specification file.

Automatically generated Laravel API documentation

The rest of this article uses a small booking API to show what Scramble can infer and where optional documentation can make the result more useful.

The Laravel API we will document

The example API lets authenticated users browse places and manage bookings:

GET /api/places
GET /api/bookings
POST /api/bookings
GET /api/bookings/{booking}
PUT /api/bookings/{booking}
DELETE /api/bookings/{booking}

The routes use Laravel Sanctum:

use App\Http\Controllers\Api\BookingsController;
use App\Http\Controllers\Api\PlacesController;
use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->group(function () {
Route::get('places', PlacesController::class);
Route::apiResource('bookings', BookingsController::class);
});

The places endpoint validates filters and returns a paginated API resource collection:

namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Resources\PlaceResource;
use App\Models\Place;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
class PlacesController extends Controller
{
public function __invoke(Request $request)
{
$request->validate([
'price_from' => ['integer'],
'price_to' => ['integer'],
'sorts' => ['array'],
'sorts.*.field' => [Rule::in(['price'])],
'sorts.*.direction' => [Rule::in(['asc', 'desc'])],
]);
$places = Place::query()
->when(
$request->integer('price_from'),
fn ($query, $price) => $query->where('price', '>=', $price),
)
->when(
$request->integer('price_to'),
fn ($query, $price) => $query->where('price', '<=', $price),
)
->paginate($request->integer('per_page', 15));
return PlaceResource::collection($places);
}
}

The resource defines the response data:

namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class PlaceResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->price,
];
}
}

The bookings controller follows the same pattern. Validation defines the accepted input, route-model binding resolves the booking, resources define successful responses, and explicit return branches describe other outcomes:

public function store(Request $request)
{
$data = $request->validate([
'place_id' => ['required', 'exists:places,id'],
'date' => ['required', 'date'],
]);
$place = Place::findOrFail($data['place_id']);
if (! $place->available($request->date('date'))) {
return response()->json([
'message' => 'Place is not available at the given date',
], 409);
}
$booking = $request->user()->bookings()->create($data);
return BookingResource::make($booking);
}
public function destroy(Booking $booking)
{
$booking->delete();
return response()->noContent();
}

What Scramble infers from Laravel code

Scramble builds the OpenAPI document from the same code Laravel uses to handle the request:

Laravel codeGenerated OpenAPI documentation
Routes and model bindingsPaths and typed path parameters
Validation rules and FormRequest classesQuery parameters and request bodies
Request input methods such as integer()Parameter types and default values
JsonResource classesReusable response schemas
Resource collections and paginatorsCollection, links, and meta schemas
Controller return statementsStatus codes and response bodies
Validation, authorization, and model bindingCommon error responses

Request parameters from validation

Because GET /api/places uses validation rules, Scramble documents price_from, price_to, and the nested sorts structure as query parameters. The call to $request->integer('per_page', 15) adds an integer per_page parameter with a default value of 15.

For POST /api/bookings, the same validation rules become a JSON request-body schema. Required rules, formats, nested fields, enums, and other supported validation constraints are reflected in the generated OpenAPI document.

The same approach works when validation is moved into a Laravel FormRequest. See the Laravel OpenAPI request documentation for the complete behavior and available overrides.

Responses from resources and return statements

Scramble analyzes PlaceResource::toArray() to build the item schema. It also recognizes that the resource collection wraps a paginator, so the generated response includes the resource array and Laravel’s pagination links and meta objects automatically.

No @response annotation is required:

return PlaceResource::collection(
Place::paginate(),
);

Automatically documented paginated resource response

The booking example produces several response types from ordinary Laravel code:

  • BookingResource::make($booking) becomes the successful resource response.
  • response()->json(..., 409) becomes a documented conflict response.
  • response()->noContent() becomes a 204 response.
  • validation contributes the standard 422 response.
  • route-model binding contributes the not-found response.

You can learn more in the Laravel OpenAPI response documentation.

Add descriptions only where code cannot provide them

Static analysis describes the API’s structure, but it cannot infer all of its business meaning. PHPDoc remains useful for human-facing summaries and descriptions; it is not required to define every request and response schema.

For example:

class PlacesController extends Controller
{
/**
* List bookable places.
*
* Filter places by price and sort the results before choosing a booking.
*/
public function __invoke(Request $request)
{
// ...
}
}

The first line becomes the operation summary and the remaining prose becomes its description.

Endpoint with an inferred schema and a custom description

Scramble groups operations by controller name by default. If that organization does not fit your API, add one or more tags to the controller:

/**
* @tags Bookings management
*/
class PlacesController extends Controller
{
// ...
}

API endpoints organized in a custom group

Document Laravel Sanctum authentication

The example routes use auth:sanctum. Scramble can derive their OpenAPI security requirements directly from that middleware.

Publish the configuration if you have not done so:

php artisan vendor:publish --provider="Dedoc\Scramble\ScrambleServiceProvider" --tag="scramble-config"

Then enable the middleware authentication strategy in config/scramble.php:

'security_strategy' =>
\Dedoc\Scramble\SecurityDocumentation\MiddlewareAuthSecurityStrategy::class,

Scramble will add a bearer security scheme, mark the Sanctum routes as protected, and document their 401 Unauthenticated response. Routes without matching authentication middleware remain public in the OpenAPI document.

Bearer authentication in the generated API documentation

For API keys, custom middleware, or multiple security schemes, see the Laravel API authentication documentation.

Customize the documentation page

The published configuration also lets you customize the API title, overview, renderer, and logo. For example:

return [
// ...
'info' => [
'version' => '1.0.0',
'description' => file_get_contents(
base_path('resources/docs/api-overview.md')
),
],
'ui' => [
'title' => 'Bookly API',
],
'renderers' => [
'elements' => [
// Keep the other Elements options from the published config.
'logo' => '/images/logo.svg',
],
],
];

The overview supports Markdown, so it can explain authentication, important workflows, or links that consumers should read before using the endpoints.

Customized Laravel API documentation overview

Control access in production

Scramble exposes the documentation automatically in local environments. To make it available in production, define Laravel’s viewApiDocs gate.

For private documentation, restrict it to the appropriate users:

use App\Models\User;
use Illuminate\Support\Facades\Gate;
public function boot(): void
{
Gate::define(
'viewApiDocs',
fn (User $user) => $user->is_admin,
);
}

If the API documentation is intentionally public, the gate can return true without requiring a user. Make that choice explicitly. The generated documentation describes the surface of your API even when the API endpoints themselves remain protected.

What else Scramble can document

The booking API covers the core workflow, but Scramble also understands many common Laravel patterns:

  • inline validation and FormRequest classes;
  • route, query, header, cookie, and request-body parameters;
  • JSON resources, conditional fields, loaded relationships, collections, and pagination;
  • JSON responses, redirects, files, streams, exceptions, and error responses;
  • Eloquent models, enums, and plain PHP objects;
  • multiple API documents and custom route selection;
  • manual attributes and extensions when application-specific behavior needs an override.

Scramble PRO adds automatic OpenAPI documentation for integrations including Spatie Laravel Data and Spatie Laravel Query Builder.

Conclusion

Automatic Laravel API documentation does not have to mean maintaining a large set of annotations. Scramble uses the routes, validation rules, resources, and return statements already present in your application to generate an OpenAPI 3.1 document.

Start with:

composer require dedoc/scramble

Then open /docs/api, review what Scramble inferred, and add human-written descriptions only where they make the API easier to understand.

Continue with the request documentation, response documentation, and authentication guide.

Scramble PRO
Comprehensive API documentation generation for Spatie’s Laravel Data, Laravel Query Builder, and other packages.