Overview¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
Generate API documentation for humans from your Laravel/Lumen/Dingo codebase. Here’s what the output looks like. There’s a Node.js version, too!
Wondering where to start? Try one of these links:
Tip
Scribe helps you generate docs automatically, but if you really want to make friendly, maintainable and testable API docs, there’s some more stuff you need to know. So I made a course for you.🤗
Features¶
- Pretty HTML documentation page, with included code samples and friendly text
- Included “Try It Out” button so users can test endpoints right from their browser
- Markdown source files that can be edited to modify docs
- Extracts body parameters information from FormRequests
- Safely calls API endpoints to generate sample responses, with authentication and other custom configuration supported
- Supports generating responses from Transformers or Eloquent API Resources
- Supports Postman collection and OpenAPI (Swagger) spec generation
- Included UI components for additional styling
- Easily customisable with custom views
- Easily extensible with custom strategies
Contents¶
Getting Started¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
Set up the package¶
First, install the package:
composer require --dev knuckleswtf/scribe
Next, publish the config file.
php artisan vendor:publish --provider="Knuckles\Scribe\ScribeServiceProvider" --tag=scribe-config
This will create a scribe.php
file in your config directory. Cool, now you’re ready to take it for a spin.
Basic configuration¶
There are two important settings we need to verify in our scribe.php
config file before trying it out.
- How do you want your documentation to be routed? This is set in the
type
key in the config file. You have two options:- As a simple set of HTML/CSS/JavaScript files (type =
static
): This generates a singleindex.html
file (plus CSS and JS assets) to your public/docs folder. The benefit of this is that it’s easy; on your local machine, you can just right-click the file and “Open in Browser”, and on your server, just visit/docs. The routing of this file does not pass through Laravel. The downside of this is that you cannot easily add authentication, or any other middleware. - As a Blade view through your Laravel app (type =
laravel
): Use this type if you want to add auth or any middleware to your docs, or if you just prefer serving it through Laravel. With this type, Scribe will automatically add the corresponding Laravel route for you, but you can customize this.
- As a simple set of HTML/CSS/JavaScript files (type =
- The
router
key. This is important so Scribe can retrieve your routes properly. If you’re using Dingo, you should change this todingo
. Otherwise, leave it aslaravel
.
Do a test run¶
Now, let’s do a test run. Run the command to generate your docs.
php artisan scribe:generate
Visit your newly generated docs:
- If you’re using
static
type, find thedocs/index.html
file in yourpublic/
folder and open it in your browser. - If you’re using
laravel
type, start your app (php artisan serve
), then visit/docs
.
There’s also a Postman collection generated for you by default. You can get it by visiting public/docs/collection.json
for static
type, and <your-app>/docs.json
for laravel
type.
If you’d like an OpenAPI (Swagger) spec, Scribe can do that too. Set openapi.enabled
in your config to true
, then run the generate
command. You can get the generated spec by visiting public/docs/openapi.yaml
for static
type, and <your-app>/docs.openapi
for laravel
type.
Great! You’ve seen what Scribe can do. Now, let’s refine our docs to match what we want.
Add general information about your API¶
First, let’s add some general info about the API. Here are some things you can customise with Scribe:
- The introductory text
- Authentication information
- Languages for the example requests
- A logo to show in your docs.
For details, check out Documenting API information.
Choose your routes¶
Next up, decide what routes you want to document. This is configured in the routes
key of scribe.php
. By default, Scribe will try to document all of your routes, so if you’re okay with that, you can leave it at that.
If you’d like to exclude some routes, there are two ways:
- In the docblock for the controller method or class, add this tag:
@hideFromAPIDocumentation
. Any routes handled by methods or controllers with this doc block tag won’t be added to the doc. - The second way is by configuring your
routes
config. Here’s what it looks like:
'routes' => [
[
'match' => [
'domains' => ['*'],
'prefixes' => ['*'],
'versions' => ['v1'],
],
'include' => [
// 'users.index', 'healthcheck*'
],
'exclude' => [
// '/health', 'admin.*'
],
'apply' => [
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'response_calls' => [
'methods' => ['GET'],
'config' => [
'app.env' => 'documentation',
'app.debug' => false,
],
'cookies' => [
// 'name' => 'value'
],
'queryParams' => [
// 'key' => 'value',
],
'bodyParams' => [
// 'key' => 'value',
],
],
],
],
],
With Scribe, you split up your routes into route groups. Each entry in the routes
array is a single group. The main purpose of these groups is so you can apply different settings to multiple endpoints in one go. For instance, for some routes, you’d like an Api-Version
header to be added to some routes, but not others, you can easily configure that here. You can also configure response calls in here.
By default, all your routes are in a single group, and we recommend leaving them like that. You can split your routes later if you realise you need to.
Add information to your routes¶
Scribe tries to figure out information about your routes, but it needs more help from you to go far. Here’s some information you can enrich:
- Groups (you can group your endpoints by domain eg “User management”, “Order information”)
- URL parameters
- Request Headers
- Body parameters
- Query parameters
- Example responses
- Fields in the response
Check out how to do this in the guide on Documenting your API.
Generate and publish¶
After making changes as needed, you can run php artisan scribe:generate
as many times as you want.
When you’re happy with how your documentation looks, you’re good to go. You can add the generated documentation to your version control and deploy as normal, and your users will be able to access it as you’ve configured.
Need advanced customization?¶
Don’t like how the template looks? Want to change how things are organized, or add a custom language for the examples? Thinking of custom ways to extract more information about your routes? Check out the guide on advanced customization.
Scribe 2: What’s new, and how to migrate¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
Scribe 2 comes with a bunch of changes focused on making the documentation process easier and the output nicer. There aren’t many “shiny” changes, mostly improvements to what works. We’ve marked required changes in the list below with a “Migration Required” label.
This is also a release announcement for Scribe for JS! Version 1 is now in out! 🎉
Start by upgrading the package version in your composer.json to ^2.0
and running composer update knuckleswtf/scribe
. Next, make a copy of your config file before publishing the new one (php artisan vendor:publish --tag=scribe-config
). Then, when you’re done applying the changes described here, copy in any custom config for your setup.
Changes in the output¶
“Try It Out”: interactive documentation with (probably) zero config ⚡💥¶
Big news: Your docs will now include a “Try t Out” button that allows users to test out an endpoint, right from their browser.
To enable this, set interactive
to true. Don’t forget to enable CORS headers for your domain in your API! Here’s the full doc.
Note: If you’ve published the views previously, you may need to re- publish them to get the included “Try It Out” functionality.
Object fields are now represented better in the docs¶
Object fields are now wrapped in a <details>
element, so you can expand the dropdown to see fields within an object. This way, it’s clearer that these are subfields within a parent.
Changes to the config file¶
Specify the default auth status of endpoints with auth.default
¶
Previously, if you had an API with all endpoints authenticated, you had to set auth.enabled
to true AND use @authenticated
on every endpoint. Pain in the ass. Now you can mark all endpoints as authenticated, by setting auth.default
to true (don’t forget to set auth.enabled
to true as well). You can also remove auth from specific endpoints with @unauthenticated
.
[Migration Required] description
replaces postman.description
¶
In 1.6.0, we added a description
config item, where you can add a description of your API. This field is used as the info.description
field in the Postman collection and OpenAPI spec, and as the first paragraph under the “Introduction” section on the docs webpage, before the intro_text
. We’ve now removed postman.description
.
How to migrate: Move the contents of your postman.description
to description
.
[Migration Required] postman.auth
has been removed in favour of postman.overrides
¶
We’ve removed postman.auth
. It didn’t make sense to have two ways of setting Postman-specific auth information (postman.auth
and postman.overrides
).
How to migrate: If you need to set Postman-specific auth now, use an auth
key in postman.overrides
:
'postman' => [
'overrides' => [
'auth' => [], // your auth info
]
]
Note that Scribe now automatically populates auth info in the collection (based on your config file), so you might not even need this.
Changes in extracting docs¶
[Migration Required] New syntax for array and object parameters¶
The old dot notation syntax was based on Laravel’s validation syntax. However, it had a few limitations in our case. It was based on PHP semantics (for instance, JSON objects are PHP arrays), which meant it didn’t fit well for documenting types. It was also unclear whether you needed or were able to document parent fields as well as individual fields.
So we’ve switched to a new syntax. It uses some elements of the old, but is clearer and easier to work with, and is based on JSON semantics. We believe this should make the output more intuitive to an end user.
Note that the new syntax only applies to docblocks. If you’re using FormRequest validation rules, you don’t need to worry about the parameter format. Scribe will transform those appropriately.
Here’s a comparison of the two, using @bodyParam
as an example:
To denote an array
cars
of elements of typeinteger
.- Old syntax:
@bodyParam cars array @bodyParam cars.* integer
- New syntax:
@bodyParam cars integer[]
To denote an object
cars
with a fieldname
of typestring
. No changes!- Syntax:
@bodyParam cars object @bodyParam cars.name string
To denote an array of objects
cars
with each item having fieldname
.- Old syntax:
@bodyParam cars.* object @bodyParam cars.*.name string
- New syntax:
@bodyParam cars object[] @bodyParam cars[].name string
Important
In the old syntax for objects and arrays of objects, the first line was optional. In the new syntax, both lines are required.
How to migrate: You’ll need to run a search through all your docblocks:
- Replace
.*.
with[].
(you can automate this part safely) - Replace
.*
fields that have anx
type with the correctx[]
type field. array
is no longer a valid type. Replace fields that have typearray
with the correctx[]
type field.- Ensure there’s a parent object for any object fields. For instance, you can’t have a
car.make string
field without acar object
field, or adogs[].name string
field without adogs object[]
.
Types are now supported for URL and query parameters¶
Previously, you couldn’t specify types for URL and query parameters. The idea was that it didn’t make sense, since they’re all passed as strings in the URL anyway. But we’ve changed that. The thinking now is that these types can hold semantic information, which matters to your API consumers—even though they’re strings in the URL, they have actual significance outside of that. You can now pass types for URL and query parameters.
How to migrate:
- In your annotations: If you don’t want to use this, no problem! All URL and query parameters will remain
string
by default. If you’d like to add types, just specify a type with@urlParam
and@queryParam
like you’d do with@bodyParam
(after the parameter name). - In custom strategies: Update any custom strategies you’ve written so they return a
type
field for each URL and query parameter
Other changes¶
add_routes
: Postman collection route changed¶
When you use laravel
type docs and have add_routes
set to true
, you get three routes added to your Laravel app: one for the webpage, one for the Postman collection and one for the OpenAPI spec. The route for the Postman collection was previously /docs.json
, but has now been renamed to /docs.postman
, to bring it in line with the OpenAPI route, which is /docs.openapi
.
@responseFile
supports other directories¶
You can now specify a file located anywhere on your machine with @responseFile
. The file path can either be an absolute path, a path relative to your project root, or a path relative to the Laravel storage directory.
Postman base URL now uses Postman variables¶
Postman collection base URL now uses a {{baseUrl}}
Postman variable, so you can easily change the base URL for all endpoints in your collection from within Postman.
[Migration Required] Plugin API changes: include ‘name’ in parameter details¶
This only applies if you have created any custom strategies. All strategies that return URL, query or body parameters or response fields must now include the name of the field as a name
field in the returned array. This means that the parameter name is going to be mentioned twice in the result from the strategy:
return [
'param1' => [ // <-- here
'name' => 'param1', // <-- and here
'description' => '...'
],
'param2' => [ // <-- here
'name' => 'param2', // <-- and here
'description' => '...'
],
];
We know it seems silly🙂, but it’s actually a small optimisation that makes things easier in the long run.
Thanks for using Scribe! We hope you have fun and write kickass API docs! And if you’d like to get better at API documentation, I’m making a course just for you: apidocsfordevs.com.
Migrating from mpociot/laravel-apidoc-generator to Scribe v1¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
There’s quite a few changes in Scribe, and this guide aims to show you the key parts you need to look out for so things don’t break. After migrating, you should also check out the list of new features.
Important
This guide describes how to migrate to Scribe version 1. Scribe 2 is the current release, so you should follow the migration guide for that when you’re done with this.
Requirements¶
- PHP version: 7.2.5+
- Laravel/Lumen version: 5.8+
Before you start¶
- Remove the old package and install the new one:
composer remove mpociot/laravel-apidoc-generator
# For Laravel
composer require --dev "knuckleswtf/scribe:^1.0.0"
# For Lumen
composer require "knuckleswtf/scribe:^1.0.0"
- Publish the new config file:
php artisan vendor:publish --provider="Knuckles\Scribe\ScribeServiceProvider" --tag=scribe-config
At this point, you should have both apidoc.php and scribe.php in your config folder. This is good, so you can easily copy your old config over and delete when you’re done.
If you’ve modified your generated Blade views, you should also publish the new ones:
php artisan vendor:publish --provider="Knuckles\Scribe\ScribeServiceProvider" --tag=scribe-views
Important
If you’ve modified the generated Markdown or added prepend/append files, you should copy them to a separate folder (not in resources/docs
). After generating the new docs, you’ll have to manually add your changes in.
After you’ve done all of the above, delete your resources/docs/
and public/docs
folders, to prevent any conflicts with the new ones we’ll generate. If you’re using laravel
type output, you can also delete resources/views/apidoc/
.
Key changes¶
High impact¶
- The
postman.name
key has been removed instead. Use thetitle
key, which will set both Postman collection name and the generated doc’s HTMl title. - The
laravel.autoload
key is nowlaravel.add_routes
, and istrue
by default. - The
laravel.docs_url
key is now/docs
by default (no longer/doc
). This means if you’re usinglaravel
docs type, your docs will be at/docs and /docs.json. - The Markdown output is now a set of files, located in
resources/docs
. The route files are located inresources/docs/groups
and are split by groups (1 group per file). - The
rebuild
command has been removed. Instead, if you want Scribe to skip the extraction phase and go straight to converting the existing Markdown to HTML, runphp artisan scribe:generate --no-extraction
.
Low impact¶
logo
is nowfalse
by default, so no logo spot will be shown. Also, if you specify a logo, it will no longer be copied to the docs folder. Rather, the path to be logo will be used as-is as thesrc
for the<img>
tag in the generated doc. This means that you must use a path that’s publicly accessible. For example, if your logo is inpublic/img
:- set
'logo' => '../img/logo.png'
forstatic
type (output folder ispublic/docs
) - set
'logo' => 'img/logo.png'
forlaravel
type
You can also use a URL instead.
- set
Advanced users¶
It’s a new package with a different name, so a few things have changed. This section is especially important if you’ve written any custom strategies or extended any of the provided classes.
- Replace all occurrences of
Mpociot\ApiDoc\Extracting\Strategies\RequestHeaders
withKnuckles\Scribe\Extracting\Strategies\Headers
- Replace all occurrences of
Mpociot\ApiDoc
withKnuckles\Scribe
- For strategies, change the type of the
$method
argument to the__invoke
method fromReflectionMethod
toReflectionFunctionAbstract
to enable support for Closure routes. It’s a superclass ofReflectionMethod
, so every other thing should work fine. - For each strategy, add a
public $stage
property and set it to the name of the stage the strategy belongs to. If you have a constructor defined, remove the$stage
argument from it. - The
requestHeaders
stage has been renamed toheaders
. - If you’ve published the views, you’ll note that they are now in a different format. See the documentation on customising the views to see how things are organised now.
That should be all. Head on to the list of new features to see what’s new. If you come across anything we’ve missed, please send in a PR!
Documenting your API¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
Scribe tries to infer information about your API from your code, but you can enrich this information in the config and by using annotations (tags in doc block comments).
Adding general information about your API¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
Authentication information¶
You can add authentication information for your API using the auth
section in scribe.php
.
Important
Scribe uses your specified authentication information in three places:
- Generating an “Authentication” section in your docs
- Adding authentication parameters to your example requests for endpoints marked as
@authenticated
(or if you have withauth.default
= true) - Adding the necessary auth parameters with the specified value to response calls only for endpoints marked as
@authenticated
(or if you have withauth.default
= true)
Here’s how you’d configure auth with a query parameter named apiKey
:
'auth' => [
'enabled' => true,
'default' => false,
'in' => 'query',
'name' => 'apiKey',
'use_value' => env('SCRIBE_API_KEY'),
'placeholder' => 'YOUR-API-KEY',
'extra_info' => 'You can retrieve your key by going to settings and clicking <b>Generate API key</b>.',
],
If apiKey
were to be a body parameter, the config would be same. Just set in
to 'body'
.
Here’s an example with a bearer token (also applies to basic auth, if you change in
to 'basic'
):
'auth' => [
'enabled' => true,
'default' => false,
'in' => 'bearer',
'name' => 'hahaha', // <--- This value is ignored for bearer and basic auth
'use_value' => env('SCRIBE_AUTH_KEY'),
'placeholder' => '{ACCESS_TOKEN}',
'extra_info' => 'You can retrieve your token by visiting your dashboard and clicking <b>Generate API token</b>.',
],
And here’s an example with a custom header:
'auth' => [
'enabled' => true,
'default' => false,
'in' => 'header',
'name' => 'Api-Key', // <--- The name of the header
'use_value' => env('SCRIBE_AUTH_KEY'),
'placeholder' => 'YOUR-API-KEY',
'extra_info' => 'You can retrieve your token by visiting your dashboard and clicking <b>Generate API token</b>.',
],
The default
field is the default behaviour of our API. If your endpoints are authenticated by default, set this to true
, then use @unauthenticated
on the method doc block if you need to turn off auth for specific endpoints. If your endpoints are open by default, leave this as false
, then use @authenticated
on the method doc block if you need to turn on auth for specific endpoints.
You can set whatever you want as the extra_info
. A good idea would be to tell your users where to get their auth key.
The use_value
field is only used by Scribe for response calls. It won’t be included in the generated output or examples.
The placeholder
is the opposite of use_value
. It will be used only as a placeholder in the generated example requests.
For more information, see the reference documentation on the auth section.
Introductory text¶
The intro_text
key in scribe.php
is where you can set the text shown to readers in the “Introduction” section. If your text is too long to be put in a config file, you can create a prepend.md
containing the intro text and put it in the resources/docs
folder.
Title¶
You can set the HTML <title>
for the generated docs webpage, Postman collection and OpenAPI spec by setting the title
key in scribe.php
. If you leave it as null, Scribe will infer it from the value of config('app.name')
.
Logo¶
Maybe you’ve got a pretty logo for your API or company, and you’d like to display that on your documentation page. No worries! To add a logo, set the logo
key in scribe.php
to the path of the logo. Here are your options:
- To point to an image on an external public URL, set
logo
to that URL. - To point to an image in your codebase, set
logo
to thepublic_path()
of the image, if you’re usinglaravel
type docs. If you’re usingstatic
type, pass in the relative path to the image from thepublic/docs
directory. For example, if your logo is in public/images, use ‘../img/logo.png’ forstatic
type and ‘img/logo.png’ forlaravel
type. - To disable the logo, set
logo
to false.
Specifying metadata about an endpoint¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
Endpoint title and description¶
To set an endpoint’s title and description, just write in the method’s docblock. The first paragraph will be used as the title, the rest as the description. Custom formatting (such as <aside>
tags) is also supported (see the Pastel docs).
For instance, this:
/**
* Add a word to the list.
*
* This endpoint allows you to add a word to the list. It's a really useful endpoint,
* and you should play around with it for a bit.
* <aside class="notice">We mean it; you really should.😕</aside>
*/
public function store(Request $request)
{
//...
}
becomes:
Note
There needs to be a blank line between the title and description.
Tip
For best results, all free text (title and description) should come before any annotations.
Grouping endpoints¶
All endpoints are grouped for easy navigation.
To add all endpoints in a controller to a group, use @group
in the controller docblock, followed by the group’s title. You can also add a description below the group.
Tip
You can also specify an @group on a single method to override the group defined at the controller level.
/**
* @group User management
*
* APIs for managing users
*/
class UserController extends Controller
{
/**
* Create a user.
*/
public function createUser()
{
}
/**
* Change a user's password.
*
* @group Account management
*/
public function changePassword()
{
}
}
Grouping endpoints is optional. Any endpoints not in a group will be placed in a default group, “Endpoints”.
Indicating authentication status¶
If you have auth.default
set to false
in your config, your endpoints will be treated as open by default. You can use the @authenticated
annotation on a method to indicate that the endpoint is authenticated.
Similarly, if you have auth.default
set to true
in your config, your endpoints will be treated as authenticated by default. You can use the @unauthenticated
annotation on a method to indicate that the endpoint is unauthenticated.
Tip
You can also specify @authenticated or @unauthenticated in a controller doc block instead to override the status for all the routes in that controller.
/**
* Create a user
*
* This endpoint lets you create a user.
* @authenticated
*
*/
public function create()
{
}
A “Requires authentication” badge will be added to that endpoint in the generated documentation.
Documenting headers for endpoints¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
To specify headers to be added to your endpoints, use the apply.headers
section of the route group in scribe.php
. For instance, if you have this config:
'routes' => [
[
'match' => [
'domains' => ['*'],
'prefixes' => ['v2/'],
],
'apply' => [
'headers' => [ 'Api-Version' => 'v2']
]
]
]
All endpoints that start with v2/
will have the header Api-Version: v2
included in their example requests and response calls.
Alternatively, you can use the @header
doc block tag, in the format @header <name> <optional example>
:
/**
* @header X-Api-Version v1
*/
Documenting query and URL parameters for an endpoint¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
Specifying query parameters¶
To describe query parameters for your endpoint, use the @queryParam
annotation on the method handling it.
The @queryParam
annotation takes the name of the parameter, an optional type, an optional “required” label, and a description.
If you don’t specify a type, Scribe will assume it’s string
. See the documentation on body parameters for a list of valid types.
Here’s an example:
/**
* @queryParam sort string Field to sort by. Defaults to 'id'.
* @queryParam fields required Comma-separated list of fields to include in the response. Example: title,published_at,is_public
* @queryParam filters[published_at] Filter by date published.
* @queryParam filters[is_public] integer Filter by whether a post is public or not. Example: 1
*/
public function listPosts()
{
// ...
}
The query parameters will be included in the generated documentation text and example requests:
If you need to handle array/object parameters, you can use the same conventions as for body parameters:
/**
* @queryParam sort string Field to sort by. Defaults to 'id'.
* @queryParam fields string[] required Comma-separated list of fields to include in the response. Example: title,published_at,is_public
* @queryParam filters object Fields to filter by
* @queryParam filters.published_at Filter by date published.
* @queryParam filters.is_public integer Filter by whether a post is public or not. Example: 1
*/
Tip
You should avoid using query parameters that are arrays or objects, because [there isn’t a standardised format for handling them](https://stackoverflow.com/a/9547490/7370522).
If you’re using a FormRequest in your controller, you can also add the @queryParam
annotation there instead, and Scribe will fetch it.
/**
* @queryParam user_id required The id of the user.
*/
class CreatePostRequest extends \Illuminate\Foundation\Http\FormRequest
{
}
// in your controller...
public function createPost(CreatePostRequest $request)
{
// ...
}
Specifying example values¶
By default, Scribe will generate a random value for each parameter, to be used in the example requests and response calls. If you’d like to use a specific example value, you can do so by adding Example: your-example-here
to the end of your description.
Tip
You can exclude a particular parameter from the generated examples by ending with No-example instead. The parameter will still be included in the text of the documentation, but it won’t be included in response calls or shown in the example requests.
For instance:
/**
* @queryParam sort Field to sort by. Defaults to 'id'. Example: published_at
* @queryParam fields required Comma-separated fields to include in the response. Example: title,published_at,id
* @queryParam filters[published_at] Filter by date published. No-example
* @queryParam filters[title] Filter by title. No-example
*/
Describing URL parameters¶
To describe parameters in the URL, use the @urlParam
annotation. For instance, if you defined your Laravel route like this:
Route::get("/post/{id}/{lang?}");
you can use this annotation to describe the id
and lang
parameters as shown below. The annotation takes the name of the parameter, an optional type, an optional “required” label, and then its description. Like with @queryParams
, a random value will be generated, but you can specify the value to be used in examples and response calls using the Example:
syntax.
If you don’t specify a type, Scribe will assume it’s string
. Valid types are string
, integer
, and number
.
/**
* @urlParam id integer required The ID of the post.
* @urlParam lang The language. Example: en
*/
public function getPost()
{
// ...
}
Note
If you want Scribe to omit an optional parameter (lang in our example) in requests and response calls, specify No-example
for the parameter.
/**
* @urlParam id required The ID of the post.
* @urlParam lang The language. No-example
*/
public function getPost()
{
// ...
}
Documenting body and file parameters for an endpoint¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
Scribe can get information about your endpoint’s body parameters in two ways:
- the fully-manual way (using the
@bodyParam
annotation) - the mostly-automatic way (using FormRequests)
The manual way: Specifying body parameters with @bodyParam¶
To describe body parameters for your endpoint, use the @bodyParam
annotation on the method handling it.
The @bodyParam
annotation takes the name of the parameter, its type, an optional “required” label, and then its description. Valid types:
string
integer
number
boolean
object
(see Handling array and object parameters below)file
(see Documenting File Uploads below)
You can append []
at the end of a type any number of times to indicate an array field (integer[]
= array of integers).
By default, Scribe will generate a random value for each parameter, to be used in the example requests and response calls. If you’d like to use a specific example value, you can do so by adding Example: your-example-here
to the end of your description.
Tip
You can exclude a particular parameter from the generated examples by ending with No-example instead. The parameter will still be included in the text of the documentation, but it won’t be included in response calls or shown in the example requests.
Here’s an example:
/**
* @bodyParam user_id int required The id of the user. Example: 9
* @bodyParam room_id string The id of the room.
* @bodyParam forever boolean Whether to ban the user forever. Example: false
* @bodyParam another_one number This won't be added to the examples. No-example
*/
public function createPost()
{
// ...
}
The body parameters will be included in the generated documentation text and example requests:
If you’re using a FormRequest in your controller, you can also add the @bodyParam
annotation there instead, and Scribe will fetch it.
/**
* @bodyParam title string The title of the post.
* @bodyParam body string required The content of the post.
*/
class CreatePostRequest extends \Illuminate\Foundation\Http\FormRequest
{
}
// in your controller...
public function createPost(CreatePostRequest $request)
{
// ...
}
Handling array and object parameters¶
Sometimes you have body parameters that are arrays or objects. To handle them in @bodyparam
, Scribe follows this convention:
For arrays: use a single field with type
<type of items>[]
. For instance, to denote an arraycars
of elements of typeinteger
:@bodyParam cars integer[]
For objects: you need a parent field with type
object
and an entry for each field, named with the dot notation<parent name>.<field>
. For instance, to denote an objectcars
with a fieldname
of typestring
:@bodyParam cars object @bodyParam cars.name string
For an array of objects, you need a parent field with type
object[]
, and an entry for each field, named with the dot notation<parent name>[].<field>
. For instance, to denote an array of objectscars
with each item having fieldname
:@bodyParam cars object[] @bodyParam cars[].name string
Important
For objects and arrays of objects, both lines are required, otherwise you might run into strange errors.
/**
* @bodyParam user object required The user details
* @bodyParam user.name string required The user's name
* @bodyParam user.age string required The user's age
* @bodyParam friend_ids int[] List of the user's friends.
* @bodyParam cars object[] List of cars
* @bodyParam cars[].year string The year the car was made. Example: 1997
* @bodyParam cars[].make string The make of the car. Example: Toyota
*/
Using FormRequests¶
If you’re using Laravel or Dingo FormRequests in your controller method, Scribe can extract information about your parameters from your validation rules. Since these rules only describe validation logic, you can also add a bodyParameters
method where you can add a description and example for each parameter.
Not all rules are supported. Here are the supported rules:
required
bool
string
int
numeric
array
file
timezone
email
url
ip
json
date
date_format
image
in
Custom rules are not supported. Scribe will ignore any rules it does not support.
For each parameter in rules()
it encounters, Scribe will:
- generate an example value that passes all the supported rules.
- generate a description that combines the supported validation rules with any description you specify in
bodyParameters()
.
Note
If you have rules that are not supported, Scribe’s generated value might not pass their validation checks. You can get around that by manually specifying an example in the bodyParameters() method.
Here’s an example:
class CreatePostRequest extends FormRequest
{
public function rules()
{
return [
'content' => 'string|required|min:100',
'title' => 'string|required|max:400',
'author_display_name' => 'string',
'author_homepage' => 'url',
'author_timezone' => 'timezone',
'author_email' => 'email|required',
'publication_date' => 'date_format:Y-m-d',
'category' => ['in:news,opinion,quiz', 'required'],
];
}
public function bodyParameters()
{
return [
'content' => [
'description' => 'Contents of the post',
],
'title' => [
'description' => 'The title of the post.',
'example' => 'My First Post',
],
'publication_date' => [
'description' => 'Date to be used as the publication date.',
],
'category' => [
'description' => 'Category the post belongs to.',
],
];
}
}
This gives:
Documenting file uploads¶
You can document file inputs by using @bodyParam
or FormRequest rules with a type file
. You can add a description and example as usual.
For files, your example should be the path to a file that exists on your machine. This path should be absolute or relative to your project directory (but not in the project root). If you don’t specify an example, Scribe will generate a fake file for example requests and response calls.
/**
* @bodyParam caption string The image caption
* @bodyParam image file required The image.
*/
Note
Adding a file parameter will automatically set the ‘Content-Type’ header in example requests and response calls to multipart/form-data.
Documenting responses from an endpoint¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
It’s helpful if your API’s consumers can see what a response should be like before writing any code. There are multiple strategies to provide example responses for your endpoint:
- describing the response using the
@response
tag - specifying a file containing the response using the
@responseFile
tag - letting Scribe generate the response by making a “response call”
- letting Scribe generate the response from the
@apiResource
tags (if you’re using Eloquent API resources) - letting Scribe generate the response from the
@transformer
tags (if you’re using Transformers)
You can use all of these strategies within the same endpoint. Scribe will display all the responses it finds.
@response
¶
You can provide an example response for an endpoint by using the @response
annotation with valid JSON:
/**
* @response {
* "id": 4,
* "name": "Jessica Jones",
* "roles": ["admin"]
* }
*/
public function show($id)
{
return User::findOrFail($id);
}
You can also specify a status code (otherwise 200 will be assumed):
/**
* @response 201 {
* "id": 4,
* "name": "Jessica Jones"
* }
*/
You can define multiple possible responses from the same endpoint using @response
. To distinguish these responses, you can use the status
and scenario
attributes.
/**
* @response scenario=success {
* "id": 4,
* "name": "Jessica Jones"
* }
* @response status=404 scenario="user not found" {
* "message": "User not found"
* }
*/
To indicate a binary response, use <<binary>>
as the value of the response, followed by a description.
/**
* @response <<binary>> The resized image
*/
@responseFile
¶
@responseFile
works similarly to @response
, but instead of inlining the response, you pass a file containing your JSON response. This can be helpful if your response body is large.
To use @responseFile
, place the response as a JSON string in a file somewhere in your project directory and specify the relative path to it. For instance, we can put this response in a file named users.get.json
in storage/responses/
:
{"id":4,"name":"Jessica Jones"}
Then in the controller:
/**
* @responseFile storage/responses/users.get.json
*/
public function getUser(int $id)
{
// ...
}
Tip
If the file is in your Laravel storage directory, you can omit the storage/
part from the file name.
You can also have multiple @responseFile
tags on a single method, distinguished by status code and/or scenarios.
/**
* @responseFile responses/users.get.json
* @responseFile status=200 scenario="when authenticated as admin" responses/user.get.admin.json
* @responseFile status=404 responses/model.not.found.json
*/
@responseFile
also allows you to overwrite parts of the response from the file with some data of your own. To do this, add the JSON you want to merge after the file path. For instance, supposing our generic “not found” response located in storage/responses/model.not.found.json
says:
{
"type": "Model",
"result": "not found"
}
We can change the type
to User
on the fly like this:
/**
* @responseFile responses/users.get.json
* @responseFile status=200 scenario="When authenticated as admin" responses/user.get.admin.json
* @responseFile status=404 responses/model.not.found.json {"type": "User"}
*/
This JSON string will be parsed and merged with the response from the file.
Generating responses automatically via response calls¶
If you don’t specify an example response using any of the other means described in this document, Scribe will attempt to get a sample response by making a HTTP request to the local endpoint (known as a “response call”).
Note
Response calls are done within a database transaction and changes are rolled back afterwards, so no data is persisted. If your database connection does not support transactions, you should add it to continue_without_database_transactions, but be warned that data from response calls will be persisted.
The configuration for response calls is located in the apply.response_calls
section for each route group in config/scribe.php
. This means that you can apply different settings for different sets of routes. Here are some important things to note:
- By default, response calls are only made for
GET
routes, but you can configure this by setting theresponse_calls.methods
key to an array of methods (e.g.['GET', 'PUT']
). Set it to['*']
to mean all methods. Leave it as an empty array to turn off response calls for that route group. - You can specify Laravel config variables to be modified for the response call. This is useful so you can prevent external services like notifications from being triggered. By default the
app.env
is set to ‘documentation’. You can add more variables in theresponse_calls.config
key.
Tip
You can also modify the environment directly by using a .env.docs
file and running scribe:generate
with --env docs
.
- By default, the package will generate dummy values for your documented query, body and file parameters and send in the request. If you specified example values using
@bodyParam
or@queryParam
, those will be used instead. You can configure additional parameters or overwrite the existing ones for the request in theresponse_calls.queryParams
,response_calls.bodyParams
, andresponse_calls.fileParams
sections. For file parameters, each value should be a valid path (absolute or relative to your project directory) to a file on the machine.
Note
If you specified No-example
for a parameter earlier, it won’t be included when making a response call.
Note
Unlike the other approaches described in this document, the ResponseCalls
strategy will only attempt to fetch a response if there are no responses with a status code of 2xx already.
@apiResource
, @apiResourceCollection
, and @apiResourceModel
¶
If your endpoint uses Eloquent API resources to generate its response, you can use the @apiResource
annotations to guide Scribe when generating a sample response. There are three available annotations:
@apiResource
, which specifies the name of the resource.@apiResourceCollection
, which should be used instead of@apiResource
if the route returns a list, either viaYourResource::collection()
ornew YourResourceCollection
). Here you’ll specify the name of the resource or resource collection.@apiResourceModel
, which specifies the Eloquent model to be passed to the resource. You should use@apiResourceModel
alongside either of the other two.
Examples:
/**
* @apiResource App\Resources\UserResource
* @apiResourceModel App\Models\User
*/
public function showUser(User $user)
{
return new UserResource($user);
}
/**
* @apiResourceCollection App\Resources\UserResource
* @apiResourceModel App\Models\User
*/
public function listUsers()
{
return UserResource::collection(User::all());
}
/**
* @apiResourceCollection App\Resources\UserCollection
* @apiResourceModel App\Models\User
*/
public function listMoreUsers()
{
return new UserCollection(User::all());
}
Scribe will generate an instance (or instances) of the model and pass the model(s) to the resource transformer to get the example response.
Tip
To understand how Scribe generates an instance of your model and how you can customize that, you should check out the section on How model instances are generated.
Paginating with API Resources¶
If your endpoint returns a paginated response, you can tell Scribe how to paginate by using the paginate
attribute on @apiResourceModel
.
/**
* @apiResourceCollection App\Resources\UserCollection
* @apiResourceModel App\Models\User paginate=10
*/
public function listMoreUsers()
{
return new UserCollection(User::paginate(10));
}
/**
* @apiResourceCollection App\Resources\UserCollection
* @apiResourceModel App\Models\User paginate=15,simple
*/
public function listMoreUsers()
{
return new UserCollection(User::simplePaginate(15));
}
@transformer, @transformerCollection, and @transformerModel
¶
If you’re using transformers (via the league/fractal package), you can tell Scribe how to generate a sample response by using the transformer annotations. There are three available annotations:
@transformer
, which specifies the name of the Transformer class.@transformerCollection
, which should be used instead of@transformer
if the route returns a list.@transformerModel
, which specifies the Eloquent model to be passed to the transformer. You should use@transformerModel
alongside either of the other two.
Tip
Specifying @transformerModel
is optional. If you don’t specify it, Scribe will attempt to use the class of the first parameter to the transformer’s transform()
method.
For example:
/**
* @transformer App\Transformers\UserTransformer
* @transformerModel App\Models\User
*/
public function showUser(int $id)
{
// ...
}
/**
* @transformerCollection App\Transformers\UserTransformer
* @transformerModel App\Models\User
*/
public function listUsers()
{
//...
}
Scribe will generate an instance (or instances) of the model and pass the model(s) to the transformer to get the example response.
Tip
To understand how Scribe generates an instance of your model and how you can customize that, you should check out the section on How model instances are generated.
If your response data is nested within a Fractal resource key, you can specify it via an additional attribute in the @transformerModel
tag.
/**
* @transformer App\Transformers\UserTransformer
* @transformerModel App\Models\User resourceKey=user
*/
Paginating with transformers¶
If your endpoint uses a paginator with the transformer, you can tell Scribe how to paginate via an additional tag, @transformerPaginator
.
/**
* @transformerCollection App\Transformers\UserTransformer
* @transformerModel App\Models\User
* @transformerPaginator League\Fractal\Pagination\IlluminatePaginatorAdapter 15
*/
public function listMoreUsers()
{
$paginator = User::paginate(15);
$users = $paginator->getCollection();
$transformer = new Fractal\Resource\Collection($users, new UserTransformer(), 'data');
$transformer->setPaginator(new IlluminatePaginatorAdapter($users));
return $fractal->createData($users)->toArray();
}
How model instances are generated¶
When generating responses from @apiResource
and @transformer
tags, Scribe needs to generate a sample model to pass to the resource or transformer. Here’s the process Scribe follows:
- First, it tries the Eloquent model factory:
factory(YourModel::class)->create()
.
Note
Scribe uses create()
instead of make()
when calling the factory, but runs it in a database transaction which is rolled back afterwards, so no data is persisted. If your database connection does not support transactions, you should add it to continue_without_database_transactions, but be warned that created models will be persisted.
- If that fails, Scribe calls
YourModel::first()
to retrieve the first model from the database. - If that fails, Scribe creates an instance using
new YourModel()
.
Applying factory states¶
If you want specific states to be applied to your model when instantiating via the Laravel model factory, you can use the states
attribute on @apiResourceModel
or @transformerModel
. Separate multiple states with a comma.
/**
* @apiResourceCollection App\Resources\UserCollection
* @apiResourceModel App\Models\User states=student,verified
*/
Loading specific relations¶
If you want specific relations to be loaded with your model when instantiating via YourModel::first()
, you can use the with
attribute on @apiResourceModel
or @transformerModel
. Separate multiple relations with a comma.
/**
* @apiResourceCollection App\Resources\UserCollection
* @apiResourceModel App\Models\User with=teacher,classmates
*/
Adding descriptions for fields in the responses¶
You can add descriptions for fields in your response by adding a @responseField
annotation to your controller method.
/**
* @responseField id The id of the newly created word
*/
Scribe figures out the type of the field from the 2xx responses for that endpoint.
Tip
You don’t need to specify the full field path if the field is inside an array of objects or wrapped in pagination data. For instance, the above annotation will work fine for all of these responses:
{ "id": 3 }
[
{ "id": 3 }
]
{
"data": [
{ "id": 3 }
]
}
If you wish, you can also specify the type of the parameter:
/**
* @responseField id integer The id of the newly created word
*/
Excluding endpoints from the documentation¶
You can exclude endpoints from the documentation by using the @hideFromAPIDocumentation
tag in the method or class doc block. Scribe will not extract any information about the route or add it to the generated docs.
Generating Documentation¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
To generate your API documentation, use the scribe:generate
artisan command.
php artisan scribe:generate
This will:
- extract information about your API and endpoints
- generate documentation about them as a series of Markdown files
- pass these Markdown files to Pastel, which wraps the Markdown files in a HTML, CSS and JavaScript template.
Viewing the generated docs¶
Accessing your generated docs depends on the type
you specified in scribe.php
:
- If you’re using
static
type, find thedocs/index.html
file in yourpublic/
folder and open that in your browser. - If you’re using
laravel
type, start your app (php artisan serve
), then visit/docs
.
Configuring interactive documentation¶
When interactive
is set to true
(which is also the default value) in your config, Scribe will add a “Try It Out” button to your endpoints so users can test them from their browser.
For this to work, though, you’ll need to make sure CORS is enabled. An easy package for this is fruitcake/laravel-cors
.
Postman collection generation¶
By default, a Postman collection file which you can import into API clients like Postman or Insomnia is generated alongside your docs. You can view it by visiting public/docs/collection.json
for static
type, and <your-app>/docs.json
for laravel
type. This link will also be added to the sidebar of your docs.
You can configure Postman collection generation in the postman
section of your scribe.php
file.
- To turn it off, set the
postman.enabled
config option to false. - To override fields in the generated collection, set the
postman.overrides
config option to your changes. You can use dot notation to update specific nested fields. For instance,['info.version' => '2.0.0']
will override the ‘versionkey in the 'info
object whenever generating.
OpenAPI (Swagger) spec generation¶
Scribe can also generate an OpenAPI spec file. This is disabled by default. You can configure this in the openapi
section of your scribe.php
file.
- To enable it, set the
openapi.enabled
config option totrue
. - To override fields in the generated spec, set the
openapi.overrides
config option to your changes. You can use dot notation to update specific nested fields. For instance,['info.version' => '2.0.0']
will override the ‘versionkey in the 'info
object whenever generating.
You can view the generated spec by visiting public/docs/openapi.yaml
for static
type, and <your-app>/docs.openapi
for laravel
type. This link will also be added to the sidebar of your docs.
Customising the environment with --env
¶
You can pass the --env
option to run this command in a specific env. For instance, if you have a .env.test
file, running scribe:generate --env test
will make Laravel use that file to populate the env for this command. This can be very useful to customise the behaviour of your app for documentation purposes and disable things like notifications when response calls are running.
Skipping the extraction phase¶
If you’ve modified the generated Markdown, and you only want Scribe to transform it to the normal HTML output, you can use the --no-extraction
flag. Scribe will skip extracting data from your routes and go straight to the writing phase, where it converts your Markdown to HTML or Blade. See Advanced Customization.
Overwriting your changes to the Markdown¶
If you’ve modified the generated Markdown manually, but you’d like to discard your changes and re-generate based on the data Scribe extracts from your routes, you can pass the --force
flag.
Memory Limitations¶
Generating docs for large APIs can be memory intensive. If you run into memory limits, consider running PHP with an increased memory limit (either by updating your CLI php.ini file or using a CLI flag):
php -d memory_limit=1G artisan scribe:generate
Further customization¶
Sometimes you need to modify the documentation after it has been generated. See the guide on customization for help on doing that.
Configuration¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
Here’s a rundown of what’s available in the config/scribe.php
file.
Tip
If you aren’t sure what an option does, it’s best to leave it set to the default.
Output settings¶
type
¶
This is the type of documentation output to generate.
static
will generate a static HTMl page in thepublic/docs
folder, so anyone can visit your documentation page by going to {yourapp.domain}/docs.laravel
will generate the documentation as a Blade view within theresources/views/scribe
folder, so you can add routing and authentication.
Note
In both instances, the source markdown file will be generated in resources/docs.
static
¶
Settings for the static
type output.
output_path
: Output folder. The HTML documentation, assets and Postman collection will be generated to this folder. Source Markdown will still be in resources/docs. Default:public/docs
.
laravel
¶
Settings for the laravel
type output.
add_routes
: Set this totrue
if you want the documentation endpoint to be automatically set up for you. Of course, you can use your own routing instead, by setting this tofalse
.docs_url
: The path for the documentation endpoint (ifadd_routes
is true). Your Postman collection (if you have that enabled) will be at this path + ‘.json’ (eg/docs.json
). Default:/docs
.middleware
: List of middleware to be attached to the documentation endpoint (ifadd_routes
is true).
base_url
¶
The base URL to be used in examples. By default, this will be the value of config('app.url')
.
intro_text
¶
The text to place in the “Introduction” section. Markdown and HTML are supported.
title
¶
The HTML <title>
for the generated documentation, and the name of the generated Postman collection. If this is null
, Scribe will infer it from config('app.name')
.
description
¶
A description for your API. This will be placed in the “Introduction” section, before the intro_text
. It will also be used as the info.description
field in the generated Postman collection and OpenAPI spec.
interactive
¶
Set this to true
if you’d like Scribe to add a “Try It Out” button to your endpoints so users can test them from their browser. Default: true
.
..Important:: For “Try It Out” to work, you’ll need to make sure CORS is enabled on your endpoints. An easy package for this is fruitcake/laravel-cors.
logo
¶
Path to an image file to use as your logo in the generated docs. This will be used as the value of the src attribute for the <img>
tag, so make sure it points to a public URL or path accessible from your web server. For best results, the image width should be 230px. Set this to false
if you’re not using a logo. Default: false
.
Important
If you’re using a relative path, remember to make it relative to your docs output location (static
type) or app URL (laravel
type). For example, if your logo is in public/img:
- for
static
type (output folder is public/docs), use ‘../img/logo.png’ - for
laravel
type, use ‘img/logo.png’
default_group
¶
When documenting your api, you use @group
annotations to group API endpoints. Endpoints which do not have a group annotation will be grouped under the default_group
. Defaults to "Endpoints"
.
example_languages
¶
For each endpoint, an example request is shown in each of the languages specified in this array. Currently only bash
, javascript
, php
and python
are supported. You can add your own language, but you must also define the corresponding Blade view (see Adding more example languages). Default: ["bash", "javascript"]
postman
¶
Along with the HTML docs, Scribe can automatically generate a Postman collection for your routes. This section is where you can configure or disable that.
For static
output, the collection will be created in public/docs/collection.json
. For laravel
output, the collection will be generated to storage/app/scribe/collection.json
. Setting laravel.add_routes
to true
will add a /docs.json
endpoint to fetch it.
enabled
: Whether or not to generate a Postman API collection. Default:true
overrides
: List of fields to apply to the generated collection. Dot notation is supported. For instance, if you’d like to override the version (in theinfo
object, you can setoverrides
to['info.version' => '2.0.0']
.
openapi
¶
Scribe can also generate an OpenAPI (Swagger) spec for your routes (disabled by default). This section is where you can configure or enable that.
Important
The OpenAPI spec is an opinionated spec that doesn’t cover all features of APIs in the wild. Scribe does its best, but there’s no guarantee that the spec generated will exactly match your API structure.
For static
output, the spec will be created in public/docs/openapi.yaml
. For laravel
output, the spec will be generated to storage/app/scribe/openapi.yaml
. Setting laravel.add_routes
to true
will add a /docs.openapi
endpoint to fetch it.
enabled
: Whether or not to generate an OpenAPI spec. Default:false
overrides
: List of fields to apply to the generated spec. Dot notation is supported. For instance, if you’d like to override the version (in theinfo
object, you can setoverrides
to['info.version' => '2.0.0']
.
Extraction settings¶
router
¶
The router to use when processing your routes. Can be laravel
or dingo
. Defaults to laravel
.
auth
¶
Authentication information about your API. This information will be used:
- to derive the text in the “Authentication” section in the generated docs
- to generate auth info in the Postman collection and OpenAPI spec
- to add the auth headers/query parameters/body parameters to the docs and example requests
- to set the auth headers/query parameters/body parameters for response calls
Here are the available settings:
enabled
: Set this totrue
if any endpoints in your API use authentication. Default:false
.default
: Specify the default behaviour of your API. If you set this totrue
, your endpoints will be authenticated by default, and you can opt out individually with the@unauthenticated
tag. If you set this tofalse
, your endpoints will NOT be authenticated by default, and you can turn on auth individually with the@authenticated
tag. Don’t forget to setauth.enabled
totrue
! Default:false
.in
: Where is the auth value meant to be sent in a request? Options:query
(for a query parameter)body
(for a body parameter)basic
(for HTTP Basic auth via an Authorization header)bearer
(for HTTP Bearer auth via an Authorization header)header
(for auth via a custom header)
name
: The name of the parameter (egtoken
,key
,apiKey
) or header (egAuthorization
,Api-Key
). Whenin
is set tobearer
orbasic
, this value will be ignored, and the header used will beAuthorization
.use_value
: The value of the parameter to be used by Scribe to authenticate response calls. This will not be included in the generated documentation. If this value is null, Scribe will use a random value.placeholder
: Placeholder your users will see for the auth parameter in the example requests. If this is empty, Scribe will generate a realistic-looking auth token instead. Defaults to: “{YOUR_AUTH_KEY}”.extra_info
: Any extra authentication-related info for your users. For instance, you can describe how to find or generate their auth credentials. Markdown and HTML are supported. This will be included in theAuthentication
section.
strategies
¶
A nested array of strategies Scribe will use to extract information about your routes at each stage. If you write or install a custom strategy, add it here under the appropriate stage. By default, this is set to:
'strategies' => [
'metadata' => [
\Knuckles\Scribe\Extracting\Strategies\Metadata\GetFromDocBlocks::class,
],
'urlParameters' => [
\Knuckles\Scribe\Extracting\Strategies\UrlParameters\GetFromLaravelAPI::class,
\Knuckles\Scribe\Extracting\Strategies\UrlParameters\GetFromUrlParamTag::class,
],
'queryParameters' => [
\Knuckles\Scribe\Extracting\Strategies\QueryParameters\GetFromQueryParamTag::class,
],
'headers' => [
\Knuckles\Scribe\Extracting\Strategies\Headers\GetFromRouteRules::class,
\Knuckles\Scribe\Extracting\Strategies\Headers\GetFromHeaderTag::class,
],
'bodyParameters' => [
\Knuckles\Scribe\Extracting\Strategies\BodyParameters\GetFromFormRequest::class,
\Knuckles\Scribe\Extracting\Strategies\BodyParameters\GetFromBodyParamTag::class,
],
'responses' => [
\Knuckles\Scribe\Extracting\Strategies\Responses\UseTransformerTags::class,
\Knuckles\Scribe\Extracting\Strategies\Responses\UseResponseTag::class,
\Knuckles\Scribe\Extracting\Strategies\Responses\UseResponseFileTag::class,
\Knuckles\Scribe\Extracting\Strategies\Responses\UseApiResourceTags::class,
\Knuckles\Scribe\Extracting\Strategies\Responses\ResponseCalls::class,
],
'responseFields' => [
\Knuckles\Scribe\Extracting\Strategies\ResponseFields\GetFromResponseFieldTag::class,
],
],
routes
¶
The routes
section is an array of items describing what routes in your application that should be included in the generated documentation.
Each item in the routes
array is a route group, an array containing rules defining what routes belong in that group, and what settings to apply to them.
match
: Here you define the rules that will be used to determine what routes in your application fall into this group. There are three kinds of rules defined here (keys in thematch
array):domains
: This key takes an array of domain names as its value. Only routes which are defined on the domains specified here will be matched as part of this group. Defaults to[*]
(routes on all domains).prefixes
: The prefixes key is similar to thedomains
key, but is based on URL path prefixes (ie. what the part starts with, after the domain name). Defaults to[*]
(all routes, regardless of path).
Important
The domains
and prefixes
keys are required for all route groups.
versions
: This only applies whenrouter
isdingo
. When using Dingo router, all routes must be specified inside versions. This means that you must specify the versions to be matched along with the domains and prefixes when describing a route group.
Important
Wildcards in versions
are not supported; you must list out all the versions you want to match.
include
: A list of patterns (route names or paths) which should be included in this group, even if they do not match the rules in thematch
section.exclude
: A list of patterns (route names or paths) which should be excluded from this group, even if they match the rules in thematch
section.
For instance, supposing our routes are set up like this:
Route::group(['domain' => 'v2-api.acme.co'], function () {
Route::resource('/apps', 'AppController@listApps');
Route::get('/users', 'UserController@listUsers')
->name('users.list');
Route::get('/users/{id}', 'UserController@getUser')
->name('users.get');
Route::get('/status', 'StatusController@getStatus')
->name('status');
});
Route::group(['domain' => 'api.acme.co'], function () {
Route::get('/getUsers', 'v1\UserController@getUsers')
->name('v1.getUsers');
Route::get('/metrics', 'PublicController@getStats')
->name('public.metrics');
});
If we only want to match endpoints on the v2-api.acme.co
domain and we want to exclude the /status
route but include the metrics route from api.acme.co
, we could use this configuration:
'match' => [
'domains' => ['api.acme.co'],
'prefixes' => ['*'],
],
'include' => ['public.metrics'],
'exclude' => ['status'],
Tip
You can use *
as a wildcard in domains, :code:`prefixes
, include
and exclude
. For instance, 'exclude' => ['users/*']
will exclude all routes with URLs starting with ‘users/’.
apply
: Theapply
section of the route group is where you specify any additional settings to be applied to those routes when generating documentation. There are a number of settings you can tweak here:headers
: Any headers you specify here will be added to the headers shown in the example requests in your documentation. They will also be included in response calls. Headers are specified as key => value strings.response_calls
: These are the settings that will be applied when making “response calls”.
Tip
By splitting your routes into groups, you can apply different settings to different routes.
faker_seed
¶
When generating example requests, this package uses the fzanninoto/faker package to generate random values. If you would like the package to generate the same example values for parameters on each run, set this to any number (eg. 1234).
Tip
Alternatively, you can set example values for parameters when documenting them.
fractal
¶
This section only applies if you’re using transformers for your API (via the league/fractal package), and documenting responses with @transformer
and @transformerCollection
. Here, you configure how responses are transformed.
serializer
: If you are using a custom serializer with league/fractal, you can specify it here. league/fractal comes with the following serializers:\League\Fractal\Serializer\ArraySerializer::class
\League\Fractal\Serializer\DataArraySerializer::class
\League\Fractal\Serializer\JsonApiSerializer::class
Leave this as
null
to use no serializer or return a simple JSON.
routeMatcher
¶
The route matcher class provides the algorithm that determines what routes should be documented. The default matcher used is the included \Knuckles\Scribe\Matching\RouteMatcher::class
, and you can provide your own custom implementation if you wish to programmatically change the algorithm. The provided matcher should be an instance of \Knuckles\Scribe\Matching\RouteMatcherInterface
.
database_connections_to_transact
¶
Scribe tries to run response calls and example model creation (API Resource and Transformer strategies) in a database transaction, and then roll it back so no changes are persisted. This item is where you specify which connections Scribe should run in transactions for.
By default, this is set to your default database connection ([config('database.default)]
), so if you only use one database connections, you should be fine. If you use multiple connections, you can add the rest to the array:
'database_connections_to_transact' => [
config('database.default'),
'pgsql',
],
continue_without_database_transactions
[deprecated]¶
Warning
This config item is deprecated and going away in v3. Use database_connections_to_transact
instead.
By default, Scribe runs response calls and example model creation in a database transaction, and then rolls them back so no changes are persisted. If one of your database drivers does not support database transactions, Scribe will log an error and exit. If you would like Scribe to proceed (and persist the data), add the database driver class name to this array. For example:
'continue_without_database_transactions' => [
Jenssegers\Mongodb\Connection::class,
],
Troubleshooting and Debugging¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
This page contains a few tips to help you figure out what’s wrong when Scribe seems to be slow or malfunctioning.
Update your installation¶
First off, try updating your installed Scribe version. Maybe your problem is due to a bug we’ve fixed in a newer release. You can see a list of releases and major changes on the changelog.
- To find the exact installed version, run
composer show knuckleswtf/scribe
- To update to the latest version, run
composer update knuckleswtf/scribe
. - To update to a specific version (example: 1.4.1), run
composer update knuckleswtf/scribe:1.4.1
.
Make sure you aren’t matching web
routes¶
Routes defined in Laravel’s web.php typically have the web
middleware, leading to strange behaviour, so make sure you’ve correctly specified the routes to be matched in your config file. See this GitHub issue.
Increase the verbosity¶
By default, Scribe will try to keep going until it processes all routes and generates your docs. If it encounters any problems while processing a route (such as a missing @responseFile
, or some invalid configuration leading to an exception being thrown), it will output a warning and the exception message, then move on to the next route.
If you need to see the full stack trace, you can run the command again with the --verbose
flag. This will also output debug messages (such as the path Scribe takes in instantiating a model).
Turn on debug mode for your app¶
Sometimes you may see a 500 null
response shown in the generated examples. This is usually because an error occurred within your application during a response call. The quickest way to debug this is by setting app.debug
to true
in your response_calls.config
section in your scribe.php
file. Alternatively, you can set APP_DEBUG=true
in your .env.docs
file and run the command with --env docs
.
Clear any cached Laravel config¶
Sometimes Laravel caches config files, and this may lead to Scribe failing with an error about a null DocumentationConfig
. To fix this, clear the config cache by running php artisan config:clear
.
Clear previously generated docs¶
Sometimes you may run into conflicts if you switch from one output type to another. While we try to prevent this happening, we don’t guarantee it. In such cases, please try clearing the old docs generated from your previous run (laravel
would be in resources/docs
and storage/docs
, static
would be in public/docs
) and then running again. We recommend copying these out to a different location, just to be safe.
Be sure you’re accessing your docs correctly¶
For laravel
type docs, you should always start your server and visit /docs (or wherever you set as your docs_url
). For static
type, you should always open the index.html
file diretly (located in public/docs
or wherever you set as your output_path
).
Customizing the generated documentation¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
Scribe offers you multiple options to customize how your documentation is rendered.
Manually modifying the documentation after generating¶
Sometimes you might need to add or remove extra information about your API that Scribe doesn’t support. You can do this by editing the generated Markdown files manually, and then letting Scribe transform them to HTML.
The Markdown files are located in your resources/docs
folder and include the following:
index.md
: This contains the front matter (see the Pastel docs) and the Introduction sectionauthentication.md
: This contains the Authentication sectiongroups/
: This folder contains your endpoints. Each Markdown file here represents a group of endpoints (the ones you specified by using@group
).
Tip
You can also add append.md
and prepend.md
files in this directory. See Specifying content to be added to the beginning or end of the documentation.
Pastel will combine these files in this order (you can also see it described in the front matter of the index.md
):
index.md
prepend.md
authentication.md
groups/*
(the files here will be included in alphabetical order)append.md
Warning
You shouldn’t create any files manually in the groups/
folder, as they will be deleted on each run,
After editing the Markdown files, you can use the scribe:generate
command to rebuild your docs.
Tip
You can pass the --no-extraction
flag to tell Scribe to skip the extraction phase and go straight to converting your Markdown to HTML.
If you run the generate
command after modifying any of the generated Markdown files (even without the --no-extraction
) flag, Scribe will not overwrite your changes to that file. To force Scribe to overwrite them, use the --force
flag.
This means that if, for instance, you modify the groups/user-management.md
file, the information about your endpoints in the “User management” group will remain the same until you use the --force
option.
Specifying content to be added to the beginning or end of the documentation¶
If you wish to automatically add the same content to the docs every time you generate (for instance, a longer introduction, a disclaimer or a list of possible error responses), you can add a prepend.md
or append.md
file to the resources/docs
folder. They will be included in the generated documentation in the order described above.
The contents of prepend.md
will be added after the Introduction section, while the contents of append.md
will show up at the end of the document.
Adding more example languages¶
For each endpoint, an example request is shown in each language configured. To add a language which is not supported by this package, you’ll have to create your own view for how an example should render. Here’s how:
First, you’ll need to publish the vendor views to to resources/views/vendor/scribe
:
- Laravel: Run
php artisan vendor:publish --provider="Knuckles\Scribe\ScribeServiceProvider" --tag=scribe-views
- Lumen: Create the
resources/views/vendor/scribe
directory and copy the contents ofvendor/knuckleswtf/scribe/resources/views/
into it.
Next, create a file called {language-name}.blade.php
(for example, ruby.blade.php
) in the partials/example-requests
directory.
You can then use Blade templates to write Markdown that describes how the example request for the language should be rendered.
In the template, you have the $baseUrl
and $route
variables available to you.
$baseUrl
is the base URL for the API (for instance, http://your-api.dev).
$route
is an array with the following keys:
methods
: an array of the HTTP methods for that routeboundUri
: the complete URL for the route, with any url parameters replaced (/users/{id}
->/users/1
)headers
: key-value array of headers to be sent with route (according to your configuration)cleanQueryParameters
: key-value array of query parameters with example values to be sent with the request.cleanBodyParameters
: key-value array of body parameters with example values to be sent with the request.fileParameters
: key-value array of file parameters with example values to be sent with the request. Each example value is an instance of\Illuminate\Http\UploadedFile
.
Important
Parameters which have been excluded from the example requests (see Specifying Example Values) will not be present in cleanQueryParameters
, cleanBodyParameters
, or fileParameters
.
Finally, add the language to the example_languages
array in your config and generate your documentation as usual.
Note
Scribe makes use of CSS from highlight.js for its syntax highlighting. The bundle we use only includes support for a bunch of the most popular languages. If your language isn’t supported (all code appears white), you can download a new CSS bundle yourself, and include your desired language. Then locate the highlight.js CSS file that Scribe outputs for you after generation, and replace that with the one you downloaded.
Customizing the code used in examples¶
Customising existing language templates follows the same process as described above: publish assets, then modify the Blade templates in resources/views/vendor/scribe/partials/example-requests
as necessary.
Changing the Markdown templates¶
If you need to go even further, you can take a look at editing the included Blade views.
Included views¶
You should see the following Blade files when you publish views:
index.blade.php
: This gets transformed to theindex.md
. It has access to the$frontmatter
and$introText
strings.authentication.blade.php
: This gets transformed into theauthentication.md
file. This has access to the following variables:$isAuthed
boolean that describes if the API has anauth
section configured- the
$authDescription
string that contains information parsed from the authentication type, and - the
$extraAuthInfo
string that contains the text inauth.extra_info
from the config file.
The following Blade files are present in the partials
directory:
frontmetter.blade.php
: This gets transformed into a string, which is then passed to theindex.blade.php
file as$frontmatter
. It has access to the following variables:$showPostmanCollectionButton
boolean that is true if Postman collection generation was enabled- the
$postmanCollectionLink
string that contains the URL to the Postman file (typically./collection.json
), and - the
$settings
array that containslogo
,languages
andtitle
.
Important
These Blade files are all configured for generating Markdown which is then turned into static HTML (by Pastel). Therefore, hardcoded and relative links are used (eg <a href="./collection.json">
). For users using laravel
type documentation, these links are afterwards replaced in the generated HTML file with the correct Blade helpers (eg <a href="{{ url('docs.json') }}" >
).
group.blade.php
: This is the template for a group of endpoints. For each group of endpoints, this file is rendered, and gets transformed into the corresponding group file (for instance, endpoints with group “User Management” are passed through this template to create the filegroups/user-management.md
). It has access to the following variables:$groupName
,$groupDescription
, and$routes
, an array containing routes in that group. Each item here contains the route information described in the plugin API, plus anoutput
item that contains the Markdown for that route.
endpoint.blade.php
: This is the template for a single endpoint. For each endpoint, it gets rendered and passed back to theWriter
class, which sets it as theoutput
key in the$route
variable before passing to the group template. It has access to the following variables:$settings
(the same settings variable passed to frontmatter),$route
: an array which contains the information extracted from the various stages (see the plugin API for details).
Included components¶
There are also a number of included components that you can utilize in your Blade files, located in the components
folder:
field-details.blade.php
: This is the template for rendering details about a field. It takes in the attributesname
,description
,type
, andrequired
. Typically, you’d use this to render a parameter in your route Blade file.
badges/auth.blade.php
: A simple ‘requires authentication’ badge. Accepts the attributeauthenticated
.
badges/http-method.blade.php
: A component to wrap a HTTP method in a badge. Takes in themethod
attribute.
badges/base.blade.php
: The base badge component, used byauth
andhttp-method
. Takes incolour
andtext
attributes, and uses Pastel’s badge classes to create a badge.
Changing the CSS styles¶
The CSS styling is provided by Pastel, which currently supports only one template. Consider making a pull request to add your alternative styles. In the meantime, you can manualy add CSS files to the generated output directory.
How Scribe works¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
Read this page if you want a deeper understanding of how Scribe works (for instance, for the purpose of contributing).
- When the
generate
command is run, the Generator fetches all your application’s routes from Laravel’s (or DIngo’s) Route facade. - Next, the RouteMatcher uses the rules in your config to determine what routes to generate documentation for, as well as extract any specific configuration for them. This configuration is passed to the next stages.
- The Generator processes each route. This means fetching the route action (controller, method) and using the configured strategies to extract the following:
- route metadata (name, description, group name, group description, auth status)
- url parameters
- body parameters
- query parameters
- headers
- fields in the response
- sample responses
- Next, the Writer uses information from these parsed routes and other configuration to generate a Markdown file via Blade templating.
- This Markdown file is passed to Pastel, which wraps them in a theme and converts them into HTML, CSS and JS.
- If enabled, a Postman collection is also generated, via the PostmanCollectionWriter.
- If enabled, an OpenAPI specification is also generated, via the OpenAPISpecWriter.
Extending functionality with plugins¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
You can use plugins to alter Scribe’s behaviour when extracting info about your endpoints. For instance, suppose all your listing endpoints support pagination query parameters pageSize
and page
, and you don’t want to annotate with @queryParam
on each method. You can create a plugin that adds this to all your query parameters. Let’s see how to do this.
The stages of route processing¶
Route processing is performed in the following stages, in this order:
- metadata (this includes
title
,description
,groupName
,groupDescription
, and authentication status (authenticated
)) - urlParameters
- queryParameters
- headers (headers to be added to example request and response calls)
- bodyParameters
- responses
- responseFields (descriptions of fields in the response)
For each stage, the Generator attempts to use various “strategies” to fetch data. The Generator will call all of the strategies configured in scribe.php
, progressively combining their results together to produce the final output of that stage.
Note
Unlike other stages, the responses stage is additive. This means that all responses from all strategies in that stage will be saved. Responses cannot overwrite each other, even if they have the same status code. By contrast, if you return a value for a body parameter from one strategy, it will overwrite any other values for that parameter gotten from previous strategies.
There are a number of strategies included with the package, so you don’t have to set up anything to get it working. Here’s what’s included in scribe.php
by default:
'strategies' => [
'metadata' => [
\Knuckles\Scribe\Extracting\Strategies\Metadata\GetFromDocBlocks::class,
],
'urlParameters' => [
\Knuckles\Scribe\Extracting\Strategies\UrlParameters\GetFromLaravelAPI::class,
\Knuckles\Scribe\Extracting\Strategies\UrlParameters\GetFromUrlParamTag::class,
],
'queryParameters' => [
\Knuckles\Scribe\Extracting\Strategies\QueryParameters\GetFromQueryParamTag::class,
],
'headers' => [
\Knuckles\Scribe\Extracting\Strategies\Headers\GetFromRouteRules::class,
\Knuckles\Scribe\Extracting\Strategies\Headers\GetFromHeaderTag::class,
],
'bodyParameters' => [
\Knuckles\Scribe\Extracting\Strategies\BodyParameters\GetFromFormRequest::class,
\Knuckles\Scribe\Extracting\Strategies\BodyParameters\GetFromBodyParamTag::class,
],
'responses' => [
\Knuckles\Scribe\Extracting\Strategies\Responses\UseTransformerTags::class,
\Knuckles\Scribe\Extracting\Strategies\Responses\UseResponseTag::class,
\Knuckles\Scribe\Extracting\Strategies\Responses\UseResponseFileTag::class,
\Knuckles\Scribe\Extracting\Strategies\Responses\UseApiResourceTags::class,
\Knuckles\Scribe\Extracting\Strategies\Responses\ResponseCalls::class,
],
'responseFields' => [
\Knuckles\Scribe\Extracting\Strategies\ResponseFields\GetFromResponseFieldTag::class,
],
],
Note
The included ResponseCalls strategy is designed to stop if a response with a 2xx status code has already been gotten via any other strategy.
Tip
Check out our community wiki for a list of strategies contributed by the community.
Creating a strategy¶
To create a strategy, create a class that extends \Knuckles\Scribe\Extracting\Strategies\Strategy
. You can do this by running the scribe:strategy
command. By default, this will place the strategy in your App\Docs\Strategies
namespace. The first argument to scribe:strategy
is the name of the strategy, the second is the stage it belongs to.
php artisan scribe:strategy AddPaginationParameters queryParameters
This creates a class like this:
<?php
namespace App\Docs\Strategies;
use Illuminate\Routing\Route;
use Knuckles\Scribe\Extracting\ParamHelpers;
use Knuckles\Scribe\Extracting\RouteDocBlocker;
use Knuckles\Scribe\Extracting\Strategies\Strategy;
use ReflectionClass;
use ReflectionFunctionAbstract;
class AddPaginationParameters extends Strategy
{
public $stage = 'queryParameters';
/**
* Trait containing some helper methods for dealing with "parameters".
* Useful if your strategy extracts information about parameters.
*/
use ParamHelpers;
/**
* @link https://scribe.readthedocs.io/en/latest/plugins.html
* @param Route $route The route which we are currently extracting queryParameters for.
* @param ReflectionClass $controller The class handling the current route.
* @param ReflectionFunctionAbstract $method The method/closure handling the current route.
* @param array $routeRules Array of rules for the ruleset which this route belongs to.
* @param array $alreadyExtractedData Data already extracted from previous stages and earlier strategies in this stage
*
* See the documentation linked above for more details about writing custom strategies.
*
* @return array|null
*/
public function __invoke(
Route $route,
ReflectionClass $controller,
ReflectionFunctionAbstract $method,
array $routeRules,
array $alreadyExtractedData = []
)
{
return null;
}
}
Alternatively, if you’re creating a strategy that you’d like people to download and install via Composer, you can generate one from this GitHub template.
Writing strategies¶
Let’s take a look at the contents of our Strategy class.
First, there’s a $stage
property that states the stage the strategy belongs too. Used internally by Scribe.
The __invoke
method of the strategy is where you extract and return data. It receives the following arguments:
- the
route
being processed (an instance of\Illuminate\Routing\Route
) - the
controller
handling the route (\ReflectionClass
) - the
method
handling the route (\ReflectionFunctionAbstract
) - the
rules
specified in thescribe.php
config file for the group this route belongs to, under theapply
section (array) alreadyExtractedData
. This contains all data for the route that has been parsed thus far in the previous stages, as well as earlier strategies in this stage.
The strategy class also has access to the current Scribe configuration via its config
property. For instance, you can retrieve the router in use with $this->config->get('router')
. You can also specify a default value to be returned if the config key is not set:
$router = $this->config->get('router', 'laravel');
Let’s add some code to make our strategy work:
public function __invoke(
Route $route,
ReflectionClass $controller,
ReflectionFunctionAbstract $method,
array $routeRules,
array $alreadyExtractedData = []
)
{
$isGetRoute = in_array('GET', $route->methods());
$isIndexRoute = strpos($route->getName(), '.index') !== false;
if ($isGetRoute && $isIndexRoute) {
return [
'page' => [
'description' => 'Page number to return.',
'required' => false,
'value' => 1,
],
'pageSize' => [
'description' => 'Number of items to return in a page. Defaults to 10.',
'required' => false,
'value' => null, // So it doesn't get included in the examples
],
];
}
return null;
}
Using your strategy¶
To use your strategy, you need to register it in the strategies
key in the scribe.php
file.
'queryParameters' => [
\Knuckles\Scribe\Extracting\Strategies\QueryParameters\GetFromQueryParamTag::class,
\App\Docs\Strategies\AddPaginationParameters::class,
],
Tip
You can also publish your strategy to Packagist. Then others can install them via composer require
and register them in their own configs.
And we’re done! Now, when we run php artisan scribe:generate
, all our GET routes that end with .index
will have the pagination parameters added.
Utilities¶
You have access to a number of tools when developing strategies. They include:
- The
RouteDocBlocker
class (in the\Knuckles\Scribe\Extracting
namespace) has a single public static method,getDocBlocksFromRoute(Route $route)
. It allows you to retrieve the docblocks for a given route. It returns an array with two keys:method
andclass
containing the docblocks for the method and controller handling the route respectively. Both are instances of\Mpociot\Reflection\DocBlock
. - The
ParamHelpers
trait (in the\Knuckles\Scribe\Extracting
namespace) can be included in your strategies. It contains a number of useful methods for working with parameters, including type casting and generating dummy values for different types. - The
DatabaseTransactionHelpers
trait (in the\Knuckles\Scribe\Extracting
namespace), which is helpful to prevent data being persisted if your strategy needs to interact with the database. This trait contains methods to start and end database transactions.
API¶
Each strategy class must implement the __invoke
method with the parameters as described above. This method must return the needed data for the intended stage, or null
to indicate failure.
- In the
metadata
stage, strategies should return an array with some or all of the following keys:
'groupName'
'groupDescription'
'title'
'description'
'authenticated' // boolean
- In the
urlParameters
,queryParameters
, andbodyParameters
stages, you can return an array with arbitrary keys. These keys will be the names of your parameters. Array keys can be indicated with Laravel’s dot notation. The value of each key should be an array with the following structure:
[
'name' => 'Parameter name',
'type' => 'valid type',
'description' => 'An optional description.',
'required => true, // or false
'value' => "An example value for the parameter",
];
See the documentation on body parameters for a list of valid types.
Tip
If you would like a parameter (body or query) to be included in the documentation but excluded from examples, set required to false and value property to null, like we did in our example above.
- In the
headers
stage, you can return a key-value array of headers. You may also get rid of already set headers by settingfalse
as the header value. - In the
responses
stage, your strategy should return an array containing the responses it was able to extract. Each item in the array should be an array representing the response, with astatus
key containing the HTTP status code, and acontent
key, which is a string containing the response. For example:
public function __invoke(Route $route, \ReflectionClass $controller, \ReflectionFunctionAbstract $method, array $routeRules, array $alreadyExtractedData = [])
{
return [
[
'content' => "Haha",
'status' => 201
],
[
'content' => '{"error": "Nope"}',
'status' => 404
],
]
}
- In the
responseFields
stage, you can return an array with arbitrary keys. These keys will be the names of fields in your response. The value of each key should be an array with the following structure:
[
'name' => '',
'type' => '',
'description' => '',
]
Contributing to Scribe¶
Attention
These docs are for Scribe v2, which is no longer maintained. See scribe.knuckles.wtf/laravel for Scribe v3.
Important
Please read this guide before sending in your contribution! There aren’t many rules, just a few guidelines to help everyone.😄
Principles¶
- Don’t submit sloppy work.
- Don’t be a dick. You don’t have to be friendly or nice, but please be respectful of other contributors.
- Focus on the contribution, not the contributor..
- Remember that people have other things to deal with in their lives, so don’t expect the maintainers to respond to your PRs and issues instantly.
Tip
Before contributing: if you’re making a code change, look through open pull requests to see if there’s one for the feature/fix already.
Updating documentation¶
Important
Don’t forget to update the documentation if your contribution changes some user-facing behaviour!
Documentation is powered by ReadTheDocs and lives as Markdown files in the docs/ folder. You can take a look at the Table of Contents in the index.md file to see what files are included. If you add a new file, please include it at a suitable position in the Table of Contents.
For screenshots and other images, you can put them in the docs/images folder and reference them via Markdown links (ie 
).
To link to a page inside another, you can use Markdown links, but then replace the “.md” with “.html”. For instance, this link) should take you to the “Need Advanced Customization?” section on the Getting Started guide.
Note
The rest of this document is only important if you’re making code changes.
Tip
You can check out How Scribe works to gain a deeper understanding that can help you when contributing.
Installing dependencies¶
Installing dependencies comes in two forms.
- To install the regular Laravel dependencies, run
composer install
. - To install the dependencies for Dingo, set the shell variable
COMPOSER=composer.dingo.json
before runningcomposer install
(ieCOMPOSER=composer.dingo.json composer install
). On Windows, you can use the NPM package cross-env to easily run a process with specific shell variables.
Running tests¶
Tip
It’s a good idea to run all tests before you modify the code. That way, if the tests fail later, you can be sure it was (probably) due to something you added.
- To run tests for Laravel, make sure the Laravel dependencies are installed by running
composer install
. Then runcomposer test
. This will run all tests excluding the ones for Dingo and stop on the first failure. - To run tests for Dingo, make sure the Laravel dependencies are installed by running
COMPOSER=composer.dingo.json composer install
. Then runCOMPOSER=composer.dingo.json composer test
. This will run only the tests for Dingo and stop on the first failure.
Tip
You can pass options to PHPUnit by putting them after a --
. For instance, filter by using composer test -- --filter can_fetch_from_responsefile_tag
.
Tip
For faster test runs, you can run the tests in parallel with composer test-parallel
. The --filter
option is not supported here, though.
Writing tests¶
Tip
You should add tests to your changes, especially where the behaviour change is critical or important for reliability. If you don’t know how, feel free to open a PR and ask for help.
Tests are located in the tests/ folder. Currently, feature tests go in the GenerateDocumentationTest
class in the base folder, unit tests go in their respective classes in the Unit
folder, and tests for included strategies go in the Strategies
folder.
Note that some of the unit and strategy tests extend PHPUnit\Framework\TestCase while others extend Orchestra\Testbench\TestCase. The first case is for tests that don’t need any special Laravel functionality. The second case is for tests that depend on some Laravel functionality or helpers (like ResponseCallsTest
that depends on Laravel routing.)
Note
Avoid tests that make assertions on the generated HTML or Markdown output. It’s a very unreliable testing approach. Instead assert on structured, consistent data like the parsed route output and Postman collection.
Linting¶
We use PHPStan for static analysis (ie to check the code for possible runtme errors wihtout executing it).
You can run the checks by running composer lint
.
If any errors are reported, you should normally fix the offending code. However, there are scenarios where we can’t avoid some errors (for instance, due to Laravel’s “magic”). In such cases, add an exception to the phpstan.neon
file, following the examples you already see there.
Making pull requests¶
Important
If your code changes how the generated documentation looks, please include “before” and “after” screenshots in your pull request. This will help the maintainers easily see the changes.
Tip
If you need a project to test the generated doc output on, you can use this. Replace the path in the repositories
section of the composer.json
to point to your local clone of Scribe.
- Add a short description to your PR (except it’s so simple it fits in the title), so the reviewer knows what to look out for before looking through your changes. If you’re fixing a bug, include a description of its behaviour and how your fix resolves it. If you’re adding a feature, explain what it is and why.
Installation¶
PHP 7.2.5 and Laravel/Lumen 6 or higher are required.
composer require --dev knuckleswtf/scribe
Laravel¶
Publish the config file by running:
php artisan vendor:publish --provider="Knuckles\Scribe\ScribeServiceProvider" --tag=scribe-config
This will create a scribe.php
file in your config
folder.
Lumen¶
- Register the service provider in your
bootstrap/app.php
:
$app->register(\Knuckles\Scribe\ScribeServiceProvider::class);
- Copy the config file from
vendor/knuckleswtf/scribe/config/scribe.php
to your project asconfig/scribe.php
. Then add to yourbootstrap/app.php
:
$app->configure('scribe');
Next up: follow the Getting Started guide to see what you can do with Scribe.