diff --git a/README.md b/README.md
index 8781a682..5f1fbdc2 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,8 @@
-## Scribe ✍
+
Scribe
+
+
+
+
Generate API documentation for humans from your Laravel codebase. [Here's what the output looks like](https://shalvah.me/TheCensorshipAPI/).
diff --git a/config/scribe.php b/config/scribe.php
index b95b3306..c5eb0fa3 100644
--- a/config/scribe.php
+++ b/config/scribe.php
@@ -54,7 +54,7 @@
* The value of the parameter. This will NOT be part of the generated documentation.
* Use it to easily auth response calls by this package. Otherwise, we'll use a random value.
*/
- 'use_value' => env('SCRIBE_API_KEY'),
+ 'use_value' => env('SCRIBE_AUTH_KEY'),
/*
* Any extra info for your users. For instance, you can describe where to find (or generate) their auth credentials.
@@ -88,10 +88,16 @@
/*
* The base URL to be used in examples and the Postman collection.
- * By default, this will be the value of config('app.url').
+ * If this is null, Scribe will use the value of config('app.url').
*/
'base_url' => null,
+ /*
+ * The HTML for the generated documentation, and the name of the generated Postman collection.
+ * If this is null, Scribe will infer it from config('app.name').
+ */
+ 'title' => null,
+
/*
* Generate a Postman collection in addition to HTML docs.
* For 'static' docs, the collection will be generated to public/docs/collection.json.
@@ -104,11 +110,6 @@
*/
'enabled' => true,
- /*
- * The name for the exported Postman collection. Default: config('app.name')." API"
- */
- 'name' => null,
-
/*
* The description for the exported Postman collection.
*/
diff --git a/docs/config.md b/docs/config.md
index d054bb3e..1cb5836d 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -1,4 +1,5 @@
# Configuration
+[IN PROGRESS]
Before you can generate your documentation, you'll need to configure a few things in your `config/scribe.php`. If you aren't sure what an option does, it's best to leave it set to the default. If you don't have this config file, see the [installation instructions](index.html#installation).
@@ -75,9 +76,7 @@ If you are using a custom serializer with league/fractal, you can specify it he
Leave this as null to use no serializer or return a simple JSON.
## `routes`
-The `routes` section is an array of items, describing what routes in your application that should have documentation generated for them. Each item in the array contains rules about what routes belong in that group, and what rules to apply to them. This allows you to apply different settings to different routes.
-
-> Note: This package does not work with Closure-based routes. If you want your route to be captured by this package, you need a controller.
+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 array contains rules about what routes belong in that group, and what rules to apply to them. This allows you to apply different settings to different routes.
Each item in the `routes` array (a route group) has keys which are explained below. We'll use this sample route definition for a Laravel app to demonstrate them:
diff --git a/docs/documenting-api-information.md b/docs/documenting-api-information.md
new file mode 100644
index 00000000..64810274
--- /dev/null
+++ b/docs/documenting-api-information.md
@@ -0,0 +1,67 @@
+# Adding general information about your API
+
+## Authentication information
+You can add authentication information for your API using the `auth` section in `scribe.php`. Scribe will use this in three places:
+- Generating an "Authentication" section in your docs
+- Adding authentication parameters o your rxample requests (for endpoints marked as `authenticated`)
+- Setting authentication information for response calls.
+
+Here's how you'd configure auth with a query parameter named `apiKey`:
+
+```php
+ 'auth' => [
+ 'enabled' => true,
+ 'in' => 'query',
+ 'name' => 'apiKey',
+ 'use_value' => env('SCRIBE_API_KEY'),
+ 'extra_info' => 'You can retrieve your key by going to settings and clicking Generate API key .',
+ ],
+```
+
+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'`):
+
+
+```php
+ 'auth' => [
+ 'enabled' => true,
+ 'in' => 'bearer',
+ 'name' => 'hahaha', // <--- This value is ignored for bearer and basic auth
+ 'use_value' => env('SCRIBE_AUTH_KEY'),
+ 'extra_info' => 'You can retrieve your token by visiting your dashboard and clicking Generate API token .',
+ ],
+```
+
+And here's an example with a custom header:
+
+
+```php
+ 'auth' => [
+ 'enabled' => true,
+ 'in' => 'header',
+ 'name' => 'Api-Key', // <--- The name of the header
+ 'use_value' => env('SCRIBE_AUTH_KEY'),
+ 'extra_info' => 'You can retrieve your token by visiting your dashboard and clicking Generate API token .',
+ ],
+```
+
+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.
+
+For more information, see the [reference documentation on the auth section](config.html#auth).
+
+
+## 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 for the generated documentation, and the name of the generated Postman collection 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 the `public_path()` of the image, if you're using `laravel` type docs. If you're using `static` type, pass in the relative path to the image from the `public/docs` directory. For example, if your logo is in public/images, use '../img/logo.png' for `static` type and 'img/logo.png' for `laravel` type.
+- To disable the logo, set `logo` to false.
diff --git a/docs/documenting-endpoint-body-parameters.md b/docs/documenting-endpoint-body-parameters.md
new file mode 100644
index 00000000..fefa6ae6
--- /dev/null
+++ b/docs/documenting-endpoint-body-parameters.md
@@ -0,0 +1,103 @@
+# Documenting parameters for an endpoint
+[IN PROGRESS]
+
+## Specifying request parameters
+To specify a list of valid parameters your API route accepts, use the `@urlParam`, `@bodyParam` and `@queryParam` annotations.
+- The `@urlParam` annotation is used for describing parameters in your URl. For instance, in a Laravel route with this URL: "/post/{id}/{lang?}", you would use this annotation to describe the `id` and `lang` parameters. It takes the name of the parameter, an optional "required" label, and then its description.
+- The `@queryParam` annotation takes the name of the parameter, an optional "required" label, and then its description.
+- The `@bodyParam` annotation takes the name of the parameter, its type, an optional "required" label, and then its description.
+
+Examples:
+
+```php
+/**
+ * @urlParam id required The ID of the post.
+ * @urlParam lang The language.
+ * @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 Just need something here.
+ * @bodyParam yet_another_param object required Some object params.
+ * @bodyParam yet_another_param.name string required Subkey in the object param.
+ * @bodyParam even_more_param array Some array params.
+ * @bodyParam even_more_param.* float Subkey in the array param.
+ * @bodyParam book.name string
+ * @bodyParam book.author_id integer
+ * @bodyParam book[pages_count] integer
+ * @bodyParam ids.* integer
+ * @bodyParam users.*.first_name string The first name of the user. Example: John
+ * @bodyParam users.*.last_name string The last name of the user. Example: Doe
+ */
+public function createPost()
+{
+ // ...
+}
+
+/**
+ * @queryParam sort Field to sort by
+ * @queryParam page The page number to return
+ * @queryParam fields required The fields to include
+ */
+public function listPosts()
+{
+ // ...
+}
+```
+
+They will be included in the generated documentation text and example requests.
+
+**Result:**
+
+
+
+
+
+### Example parameters
+For each parameter in your request, this package will generate a random value to be used in the example requests. If you'd like to specify an example value, you can do so by adding `Example: your-example` to the end of your description. For instance:
+
+```php
+ /**
+ * @queryParam location_id required The id of the location.
+ * @queryParam user_id required The id of the user. Example: me
+ * @queryParam page required The page number. Example: 4
+ * @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
+ */
+```
+
+You can also exclude a particular parameter from the generated examples (for all languages) by annotating it with `No-example`. For instance:
+```php
+ /**
+ * @queryParam location_id required The id of the location. Example: 1
+ * @queryParam user_id required The id of the user. No-example
+ * @queryParam page required The page number. Example: 4
+ */
+```
+Outputs:
+```bash
+curl -X GET -G "https://example.com/api?location_id=1&page=4"
+```
+
+Note: You can also add the `@queryParam` and `@bodyParam` annotations to a `\Illuminate\Foundation\Http\FormRequest` subclass instead, if you are using one in your controller method
+
+```php
+/**
+ * @queryParam user_id required The id of the user. Example: me
+ * @bodyParam title string required The title of the post.
+ * @bodyParam body string required The content of the post.
+ * @bodyParam type string The type of post to create. Defaults to 'textophonious'.
+ * @bodyParam author_id int the ID of the author. Example: 2
+ * @bodyParam thumbnail image This is required if the post type is 'imagelicious'.
+ */
+class MyRequest extends \Illuminate\Foundation\Http\FormRequest
+{
+
+}
+
+// in your controller...
+public function createPost(MyRequest $request)
+{
+ // ...
+}
+```
diff --git a/docs/documenting-endpoint-headers.md b/docs/documenting-endpoint-headers.md
new file mode 100644
index 00000000..2a439867
--- /dev/null
+++ b/docs/documenting-endpoint-headers.md
@@ -0,0 +1,19 @@
+# Documenting headers for endpoints
+
+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:
+
+```php
+ '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.
diff --git a/docs/documenting-endpoint-metadata.md b/docs/documenting-endpoint-metadata.md
new file mode 100644
index 00000000..23b78c70
--- /dev/null
+++ b/docs/documenting-endpoint-metadata.md
@@ -0,0 +1,82 @@
+# Specifying metadata about an endpoint
+
+## 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 `` tags) is also supported (see the [Pastel docs](http://github.com/knuckleswtf/pastel))
+
+For instance, this:
+
+```php
+ /**
+ * 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.
+ * We mean it; you really should.😕
+ */
+ public function store(Request $request)
+ {
+ //...
+ }
+```
+
+becomes:
+
+
+
+## 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.
+
+You can also specify an `@group` on a single method to override the group defined at the controller level.
+
+```php
+/**
+ * @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
+You can use the `@authenticated` annotation on a method to indicate if the endpoint is authenticated. A "Requires authentication" badge will be added to that route in the generated documentation.
+
+If all the routes in a controller are authenticated, you can specify `@authenticated` in the controller doc block instead.
+
+```php
+ /**
+ * Create a user
+ * This endpoint lets you create a user.
+ * @authenticated
+ *
+ */
+ public function create()
+ {
+ }
+```
+
+
diff --git a/docs/documenting-endpoint-query-parameters.md b/docs/documenting-endpoint-query-parameters.md
new file mode 100644
index 00000000..3901e903
--- /dev/null
+++ b/docs/documenting-endpoint-query-parameters.md
@@ -0,0 +1,101 @@
+# Documenting parameters for an endpoint
+
+## Specifying query parameters
+To describe query parameters for your endpoint, use the `@queryParam` annotation.
+
+The `@queryParam` annotation takes the name of the parameter, an optional "required" label, and a description.
+
+Examples:
+
+```php
+/**
+ * @queryParam sort Field to sort by. Defaults to 'id'.
+ * @queryParam fields required Comma-separated fields to include in the response
+ * @queryParam filters[published_at] Filter by date published.
+ * @queryParam filters[title] Filter by title.
+ */
+public function listPosts()
+{
+ // ...
+}
+```
+
+They will be included in the generated documentation text and example requests:
+
+
+
+
+
+
+If you're using a FormRequwst in your controller, you can also add the `@queryParam` annotation there instead, and Scribe will fetch it.
+
+```php
+/**
+ * @queryParam user_id required The id of the user. Example: me
+ */
+class MyRequest extends \Illuminate\Foundation\Http\FormRequest
+{
+
+}
+
+// in your controller...
+public function createPost(MyRequest $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` to the end of your description.
+
+You can also exclude a particular parameter from the generated examples by ending with `No-example` instead. This will also prevent the parameter from being sent along in response calls.
+
+For instance:
+
+```php
+ /**
+ * @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:
+
+```php
+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 "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.
+
+```php
+/**
+ * @urlParam id required The ID of the post.
+ * @urlParam lang The language. Example: en
+ */
+public function getPost()
+{
+ // ...
+}
+```
+
+
+
+ If you specify `No-example` for a parameter that's optional (`lang` in our example), Scribe will omit that parameter in requests and response calls.
+
+```php
+/**
+ * @urlParam id required The ID of the post.
+ * @urlParam lang The language. No-example
+ */
+public function getPost()
+{
+ // ...
+}
+```
+
+
diff --git a/docs/documenting-endpoint-responses.md b/docs/documenting-endpoint-responses.md
new file mode 100644
index 00000000..44897dd1
--- /dev/null
+++ b/docs/documenting-endpoint-responses.md
@@ -0,0 +1,209 @@
+
+# Documenting endpoint responses
+[IN PROGRESS]
+
+## Providing an example response
+You can provide an example response for a route. This will be displayed in the examples section. There are several ways of doing this.
+
+### @response
+You can provide an example response for a route by using the `@response` annotation with valid JSON:
+
+```php
+/**
+ * @response {
+ * "id": 4,
+ * "name": "Jessica Jones",
+ * "roles": ["admin"]
+ * }
+ */
+public function show($id)
+{
+ return User::find($id);
+}
+```
+
+Moreover, you can define multiple `@response` tags as well as the HTTP status code related to a particular response (if no status code set, `200` will be assumed):
+```php
+/**
+ * @response {
+ * "id": 4,
+ * "name": "Jessica Jones",
+ * "roles": ["admin"]
+ * }
+ * @response 404 {
+ * "message": "No query results for model [\App\User]"
+ * }
+ */
+public function show($id)
+{
+ return User::findOrFail($id);
+}
+```
+
+### @apiResource, @apiResourceCollection, and @apiResourceModel
+If your controller method uses [Eloquent API resources](https://laravel.com/docs/5.8/eloquent-resources), you can use the apiResource annotations to guide the package when generating a sample response. The `@apiResource` tag specifies the name of the resource. Use `@apiResourceCollection` instead if the route returns a list. This works with both regular `JsonResource` objects and `ResourceCollection` objects.
+
+ The `@apiResourceModel` specifies the Eloquent model to be passed to the resource. The package will attempt to generate an instance of the model for the resource from the Eloquent model factory. If that fails, the package will call `::first()` to retrieve the first model from the database. If that fails, it will create an instance using `new`.
+
+Examples:
+
+```php
+
+/**
+ * @apiResourceCollection Knuckles\Scribe\Tests\Fixtures\UserResource
+ * @apiResourceModel Knuckles\Scribe\Tests\Fixtures\User
+ */
+public function listUsers()
+{
+ return UserResource::collection(User::all());
+}
+
+/**
+ * @apiResourceCollection Knuckles\Scribe\Tests\Fixtures\UserCollection
+ * @apiResourceModel Knuckles\Scribe\Tests\Fixtures\User
+ */
+public function listMoreUsers()
+{
+ return new UserCollection(User::all());
+}
+
+/**
+ * @apiResourceCollection Knuckles\Scribe\Tests\Fixtures\UserResource
+ * @apiResourceModel Knuckles\Scribe\Tests\Fixtures\User
+ */
+public function showUser(User $user)
+{
+ return new UserResource($user);
+}
+```
+
+### @transformer, @transformerCollection, and @transformerModel
+You can define the transformer that is used for the result of the route using the `@transformer` tag (or `@transformerCollection` if the route returns a list). The package will attempt to generate an instance of the model to be transformed using the following steps, stopping at the first successful one:
+
+1. Check if there is a `@transformerModel` tag to define the model being transformed. If there is none, use the class of the first parameter to the transformer's `transform()` method.
+2. Get an instance of the model from the Eloquent model factory
+2. If the parameter is an Eloquent model, load the first from the database.
+3. Create an instance using `new`.
+
+Finally, it will pass in the model to the transformer and display the result of that as the example response.
+
+For example:
+
+```php
+/**
+ * @transformercollection \App\Transformers\UserTransformer
+ * @transformerModel \App\User
+ */
+public function listUsers()
+{
+ //...
+}
+
+/**
+ * @transformer \App\Transformers\UserTransformer
+ */
+public function showUser(User $user)
+{
+ //...
+}
+
+/**
+ * @transformer \App\Transformers\UserTransformer
+ * @transformerModel \App\User
+ */
+public function showUser(int $id)
+{
+ // ...
+}
+```
+For the first route above, this package will generate a set of two users then pass it through the transformer. For the last two, it will generate a single user and then pass it through the transformer.
+
+> Note: for transformer support, you need to install the league/fractal package
+
+```bash
+composer require league/fractal
+```
+
+### @responseFile
+
+For large response bodies, you may want to use a dump of an actual response. You can put this response in a file (as a JSON string) within your Laravel storage directory and link to it. For instance, we can put this response in a file named `users.get.json` in `storage/responses`:
+
+```
+{"id":5,"name":"Jessica Jones","gender":"female"}
+```
+
+Then in your controller, link to it by:
+
+```php
+/**
+ * @responseFile responses/users.get.json
+ */
+public function getUser(int $id)
+{
+ // ...
+}
+```
+The package will parse this response and display in the examples for this route.
+
+Similarly to `@response` tag, you can provide multiple `@responseFile` tags along with the HTTP status code of the response:
+```php
+/**
+ * @responseFile responses/users.get.json
+ * @responseFile 404 responses/model.not.found.json
+ */
+public function getUser(int $id)
+{
+ // ...
+}
+```
+
+## Generating responses automatically
+If you don't specify an example response using any of the above means, this package will attempt to get a sample response by making a request to the route (a "response call"). A few things to note about response calls:
+
+- Response calls are done within a database transaction and changes are rolled back afterwards.
+
+- The configuration for response calls is located in the `config/scribe.php`. They are configured within the `apply.response_calls` section for each route group, allowing you to apply different settings for different sets of routes.
+
+- By default, response calls are only made for GET routes, but you can configure this. Set the `methods` key to an array of methods or '*' to mean all methods. Leave it as an empty array to turn off response calls for that route group.
+
+- You can set Laravel config variables. 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 the `config` key.
+
+- By default, the package will generate dummy values for your documented body and query 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 the `queryParams`, and `bodyParams` sections.
+
+- The `ResponseCalls` strategy will only attempt to fetch a response if there are no responses with a status code of 2xx already.
+
+
+
+## Documenting responses
+ This functionality is provided by default by the `UseResponseFieldTags` strategy. You use it by adding a `@responseField` annotation to your controller method.
+
+```
+@responseField id integer The id of the newly created user
+```
+
+Note that this also works the same way for array responses. So if your response is an array of objects, you should only mention the keys of the objects inside the array. So the above annotation will work fine for both this response:
+
+```
+{
+ "id": 3
+}
+```
+
+and this:
+
+```
+[
+ { "id": 3 }
+]
+```
+
+You can also omit the type of the field. Scribe will try to figure it out from the 2xx responses for that endpoint. So this gives the same result:
+
+```
+@responseField id integer The id of the newly created user
+```
+
+Result:
+
+
+
diff --git a/docs/documenting.md b/docs/documenting.md
index 228337fb..9ab1ce58 100644
--- a/docs/documenting.md
+++ b/docs/documenting.md
@@ -1,393 +1,10 @@
-# Documenting Your API
-This package generates documentation from your code using mainly annotations (in doc block comments).
-
-## Grouping endpoints
-All endpoints are grouped for easy organization. Using `@group` in a controller doc block creates a Group within the API documentation. All routes handled by that controller will be grouped under this group in the table of contents shown in the sidebar.
-
-The short description after the `@group` should be unique to allow anchor tags to navigate to this section. A longer description can be included below. Custom formatting and `` tags are also supported. (see the [Pastel docs](http://github.com/knuckleswtf/pastel/README.md))
-
- > Note: using `@group` is optional. Ungrouped routes will be placed in a default group.
-
-Above each route in the controller, you should have a doc block. This should include a unique short description as the first entry. An optional second entry can be added with further information. Both descriptions will appear in the API documentation in a different format as shown below.
-
-You can also specify an `@group` on a single method to override the group defined at the controller level.
-
-```php
-/**
- * @group User management
- *
- * APIs for managing users
- */
-class UserController extends Controller
-{
-
- /**
- * Create a user
- *
- * [Insert optional longer description of the API endpoint here.]
- *
- */
- public function createUser()
- {
-
- }
-
- /**
- * @group Account management
- *
- */
- public function changePassword()
- {
-
- }
-}
-```
-
-**Result:**
-
-
-
-## Specifying request parameters
-To specify a list of valid parameters your API route accepts, use the `@urlParam`, `@bodyParam` and `@queryParam` annotations.
-- The `@urlParam` annotation is used for describing parameters in your URl. For instance, in a Laravel route with this URL: "/post/{id}/{lang?}", you would use this annotation to describe the `id` and `lang` parameters. It takes the name of the parameter, an optional "required" label, and then its description.
-- The `@queryParam` annotation takes the name of the parameter, an optional "required" label, and then its description.
-- The `@bodyParam` annotation takes the name of the parameter, its type, an optional "required" label, and then its description.
-
-Examples:
-
-```php
-/**
- * @urlParam id required The ID of the post.
- * @urlParam lang The language.
- * @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 Just need something here.
- * @bodyParam yet_another_param object required Some object params.
- * @bodyParam yet_another_param.name string required Subkey in the object param.
- * @bodyParam even_more_param array Some array params.
- * @bodyParam even_more_param.* float Subkey in the array param.
- * @bodyParam book.name string
- * @bodyParam book.author_id integer
- * @bodyParam book[pages_count] integer
- * @bodyParam ids.* integer
- * @bodyParam users.*.first_name string The first name of the user. Example: John
- * @bodyParam users.*.last_name string The last name of the user. Example: Doe
- */
-public function createPost()
-{
- // ...
-}
-
-/**
- * @queryParam sort Field to sort by
- * @queryParam page The page number to return
- * @queryParam fields required The fields to include
- */
-public function listPosts()
-{
- // ...
-}
-```
-
-They will be included in the generated documentation text and example requests.
-
-**Result:**
-
-
-
-
-
-### Example parameters
-For each parameter in your request, this package will generate a random value to be used in the example requests. If you'd like to specify an example value, you can do so by adding `Example: your-example` to the end of your description. For instance:
-
-```php
- /**
- * @queryParam location_id required The id of the location.
- * @queryParam user_id required The id of the user. Example: me
- * @queryParam page required The page number. Example: 4
- * @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
- */
-```
-
-You can also exclude a particular parameter from the generated examples (for all languages) by annotating it with `No-example`. For instance:
-```php
- /**
- * @queryParam location_id required The id of the location. Example: 1
- * @queryParam user_id required The id of the user. No-example
- * @queryParam page required The page number. Example: 4
- */
-```
-Outputs:
-```bash
-curl -X GET -G "https://example.com/api?location_id=1&page=4"
-```
-
-Note: You can also add the `@queryParam` and `@bodyParam` annotations to a `\Illuminate\Foundation\Http\FormRequest` subclass instead, if you are using one in your controller method
-
-```php
-/**
- * @queryParam user_id required The id of the user. Example: me
- * @bodyParam title string required The title of the post.
- * @bodyParam body string required The content of the post.
- * @bodyParam type string The type of post to create. Defaults to 'textophonious'.
- * @bodyParam author_id int the ID of the author. Example: 2
- * @bodyParam thumbnail image This is required if the post type is 'imagelicious'.
- */
-class MyRequest extends \Illuminate\Foundation\Http\FormRequest
-{
-
-}
-
-// in your controller...
-public function createPost(MyRequest $request)
-{
- // ...
-}
-```
-
-## Indicating authentication status
-You can use the `@authenticated` annotation on a method to indicate if the endpoint is authenticated. A "Requires authentication" badge will be added to that route in the generated documentation.
-
-Just like `@group` annotation, you can also specify an `@authenticated` on a single method to override the authenticated status defined at the controller level.
-
-```php
-/**
- * @authenticated
- *
- * APIs for managing users
- */
-class UserController extends Controller
-{
-
- /**
- * Create a user
- *
- * [Insert optional longer description of the API endpoint here.]
- *
- */
- public function createUser()
- {
-
- }
-
- /**
- * @group Account management
- *
- */
- public function changePassword()
- {
-
- }
-}
-```
-
-Now all the methods under this controller will have "Requires authentication" badge enabled.
-
-## Providing an example response
-You can provide an example response for a route. This will be displayed in the examples section. There are several ways of doing this.
-
-### @response
-You can provide an example response for a route by using the `@response` annotation with valid JSON:
-
-```php
-/**
- * @response {
- * "id": 4,
- * "name": "Jessica Jones",
- * "roles": ["admin"]
- * }
- */
-public function show($id)
-{
- return User::find($id);
-}
-```
-
-Moreover, you can define multiple `@response` tags as well as the HTTP status code related to a particular response (if no status code set, `200` will be assumed):
-```php
-/**
- * @response {
- * "id": 4,
- * "name": "Jessica Jones",
- * "roles": ["admin"]
- * }
- * @response 404 {
- * "message": "No query results for model [\App\User]"
- * }
- */
-public function show($id)
-{
- return User::findOrFail($id);
-}
-```
-
-### @apiResource, @apiResourceCollection, and @apiResourceModel
-If your controller method uses [Eloquent API resources](https://laravel.com/docs/5.8/eloquent-resources), you can use the apiResource annotations to guide the package when generating a sample response. The `@apiResource` tag specifies the name of the resource. Use `@apiResourceCollection` instead if the route returns a list. This works with both regular `JsonResource` objects and `ResourceCollection` objects.
-
- The `@apiResourceModel` specifies the Eloquent model to be passed to the resource. The package will attempt to generate an instance of the model for the resource from the Eloquent model factory. If that fails, the package will call `::first()` to retrieve the first model from the database. If that fails, it will create an instance using `new`.
-
-Examples:
-
-```php
-
-/**
- * @apiResourceCollection Knuckles\Scribe\Tests\Fixtures\UserResource
- * @apiResourceModel Knuckles\Scribe\Tests\Fixtures\User
- */
-public function listUsers()
-{
- return UserResource::collection(User::all());
-}
-
-/**
- * @apiResourceCollection Knuckles\Scribe\Tests\Fixtures\UserCollection
- * @apiResourceModel Knuckles\Scribe\Tests\Fixtures\User
- */
-public function listMoreUsers()
-{
- return new UserCollection(User::all());
-}
-
-/**
- * @apiResourceCollection Knuckles\Scribe\Tests\Fixtures\UserResource
- * @apiResourceModel Knuckles\Scribe\Tests\Fixtures\User
- */
-public function showUser(User $user)
-{
- return new UserResource($user);
-}
-```
-
-### @transformer, @transformerCollection, and @transformerModel
-You can define the transformer that is used for the result of the route using the `@transformer` tag (or `@transformerCollection` if the route returns a list). The package will attempt to generate an instance of the model to be transformed using the following steps, stopping at the first successful one:
-
-1. Check if there is a `@transformerModel` tag to define the model being transformed. If there is none, use the class of the first parameter to the transformer's `transform()` method.
-2. Get an instance of the model from the Eloquent model factory
-2. If the parameter is an Eloquent model, load the first from the database.
-3. Create an instance using `new`.
-
-Finally, it will pass in the model to the transformer and display the result of that as the example response.
-
-For example:
-
-```php
-/**
- * @transformercollection \App\Transformers\UserTransformer
- * @transformerModel \App\User
- */
-public function listUsers()
-{
- //...
-}
-
-/**
- * @transformer \App\Transformers\UserTransformer
- */
-public function showUser(User $user)
-{
- //...
-}
-
-/**
- * @transformer \App\Transformers\UserTransformer
- * @transformerModel \App\User
- */
-public function showUser(int $id)
-{
- // ...
-}
-```
-For the first route above, this package will generate a set of two users then pass it through the transformer. For the last two, it will generate a single user and then pass it through the transformer.
-
-> Note: for transformer support, you need to install the league/fractal package
-
-```bash
-composer require league/fractal
-```
-
-### @responseFile
-
-For large response bodies, you may want to use a dump of an actual response. You can put this response in a file (as a JSON string) within your Laravel storage directory and link to it. For instance, we can put this response in a file named `users.get.json` in `storage/responses`:
-
-```
-{"id":5,"name":"Jessica Jones","gender":"female"}
-```
-
-Then in your controller, link to it by:
-
-```php
-/**
- * @responseFile responses/users.get.json
- */
-public function getUser(int $id)
-{
- // ...
-}
-```
-The package will parse this response and display in the examples for this route.
-
-Similarly to `@response` tag, you can provide multiple `@responseFile` tags along with the HTTP status code of the response:
-```php
-/**
- * @responseFile responses/users.get.json
- * @responseFile 404 responses/model.not.found.json
- */
-public function getUser(int $id)
-{
- // ...
-}
-```
-
-## Generating responses automatically
-If you don't specify an example response using any of the above means, this package will attempt to get a sample response by making a request to the route (a "response call"). A few things to note about response calls:
-
-- Response calls are done within a database transaction and changes are rolled back afterwards.
-
-- The configuration for response calls is located in the `config/scribe.php`. They are configured within the `apply.response_calls` section for each route group, allowing you to apply different settings for different sets of routes.
-
-- By default, response calls are only made for GET routes, but you can configure this. Set the `methods` key to an array of methods or '*' to mean all methods. Leave it as an empty array to turn off response calls for that route group.
-
-- You can set Laravel config variables. 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 the `config` key.
-
-- By default, the package will generate dummy values for your documented body and query 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 the `queryParams`, and `bodyParams` sections.
-
-- The `ResponseCalls` strategy will only attempt to fetch a response if there are no responses with a status code of 2xx already.
-
-
-
-## Documenting responses
- This functionality is provided by default by the `UseResponseFieldTags` strategy. You use it by adding a `@responseField` annotation to your controller method.
-
-```
-@responseField id integer The id of the newly created user
-```
-
-Note that this also works the same way for array responses. So if your response is an array of objects, you should only mention the keys of the objects inside the array. So the above annotation will work fine for both this response:
-
-```
-{
- "id": 3
-}
-```
-
-and this:
-
-```
-[
- { "id": 3 }
-]
-```
-
-You can also omit the type of the field. Scribe will try to figure it out from the 2xx responses for that endpoint. So this gives the same result:
-
-```
-@responseField id integer The id of the newly created user
-```
-
-Result:
-
-
-
+# Documenting your API
+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).
+
+Here's some of the information you can customise:
+- [General API information](documenting-api-information.html)
+- [Endpoint metadata](documenting-endpoint-metadata.html) (endpoint group, title, description, authentication status)
+- [Headers to be sent in requests to the endpoint](documenting-endpoint-headers.html)
+- [Query parameters and URL parameters to be sent in requests to the endpoint](documenting-endpoint-query-parameters.html)
+- [Body parameters and files to be sent in requests to the endpoint](documenting-endpoint-body-parameters.html)
+- [Example responses returned from the endpoint](documenting-endpoint-responses.html)
diff --git a/docs/generating-documentation.md b/docs/generating-documentation.md
index ee0d4966..05a027f6 100644
--- a/docs/generating-documentation.md
+++ b/docs/generating-documentation.md
@@ -1,4 +1,5 @@
# Generating Documentation
+[IN PROGRESS]
To generate your API documentation, use the `scribe:generate` artisan command.
diff --git a/docs/guide-getting-started.md b/docs/guide-getting-started.md
index 2382772a..21df23f2 100644
--- a/docs/guide-getting-started.md
+++ b/docs/guide-getting-started.md
@@ -4,7 +4,7 @@
First, install the package:
```bash
-composer install knuckleswtf/scribe
+composer require --dev knuckleswtf/scribe
```
Next, publish the config file.
@@ -15,8 +15,43 @@ php artisan vendor:publish --provider="Knuckles\Scribe\ScribeServiceProvider" --
This will create a `scribe.php` file in your config directory. Cool, now you're ready to take it for a spin.
-## First: What routes do I want to document?
-The first thing to do is decide what routes you want to document. By default, Scribe will try to document all of your routes. You should take a moment to configure this in the `scribe.php`. Let's look at the `routes` section. It looks like this (with some comments):
+## 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 single `index.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.
+- The `router` key. This is important so Scribe can retrieve your routes properly. If you're using Dingo, you should change this to `dingo`. Otherwise, leave it as `laravel`.
+
+## Do a test run
+Now, let's do a test run. Run the command to generate your docs.
+
+```bash
+php artisan scribe:generate
+```
+
+Open up your docs in your browser. If you're using `static` type, just find the `docs/index.html` file in your `public/` folder. If you're using `laravel` type, start your app (`php artisan serve`), then visit `/docs`. You should see your docs show up nicely.
+
+There's also a Postman collection generated for you by default. You can get it by visiting `docs/collection.json` for `static` type, and `/docs.json` 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 []().
+
+## 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 DocBlock tag won't be added to the doc.
+
+- The second way is by configuring your `routes` config. Here's what it looks like:
```php
@@ -57,44 +92,19 @@ The first thing to do is decide what routes you want to document. By default, Sc
],
],
],
-
-```
-
-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. 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.
-
-Another important setting is the `router` key. If you're using Dingo, you should change this to `dingo`.
-
-The last important setting to take note of is `apply.response_calls`. A "response call" is Scribe hitting your API to try to generate an example response to display in your docs. The package tries to play it safe by using database transactions (so no data is modified). Additionally, response calls are only enabled for `GET` requests by default. You can configure the behaviour of response calls here. For now, we can leave them as on for GETs only.
-
-## Pick a documentation type
-We're almost ready to try it out. Just one more thing. How do you want your documentation to be routed? This is set in the `type` key in the config. You have two options:
-- As a simple set of HTML/CSS/JavaScript files (type = `static`): This generates a single `index.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.
-
-
-## Do a test run
-Now, let's do a test run. Run the command to generate your docs.
-
-```bash
-php artisan scribe:generate
```
-Open up your docs in your browser. If you're using `static` type, just find the `docs/index.html` file in your public/ folder. If you're using `laravel` type, start your app (`php artisan serve`), then visit `/docs`. You should see your docs show up nicely.
+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](documenting-endpoint-responses.html#response-calls) in here.
-There's also a Postman collection generated for you by default. You can get it by visiting `/docs/collection.json` for `static` type, and `/docs.json` for `laravel` type.
+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 about your API
-Now you can add more detail to your documentation. Here are some things you can customise:
-- The introductory text
-- Authentication information
-- Languages for the example requests
-- A logo to show in your docs.
+[Here's the full documentation on configuring routes](config.html#routes).
-For details, check out []().
+The last important setting to take note of is `apply.response_calls`. A "response call" is Scribe hitting your API to try to generate an example response to display in your docs. The package tries to play it safe by using database transactions (so no data is modified). Additionally, response calls are only enabled for `GET` requests by default. You can configure the behaviour of response calls here. For now, we can leave them as on for GETs only.
## 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)
+- Groups (you can group your endpoints by domain eg "User management", "Order information")
- URL parameters
- Request Headers
- Body parameters
@@ -102,13 +112,12 @@ Scribe tries to figure out information about your routes, but it needs more help
- Example responses
- Fields in the response
-Check out how to do this in the guide on [Documenting your API]().
+Check out how to do this in the guide on [Documenting your API](documenting.html).
## Generate and publish
-After making changes as needed, you can run `php artisan scribe:generate` as many times as you want. You should also check out the [Helpful Tips]() guide.
+After making changes as needed, you can run `php artisan scribe:generate` as many times as you want. You should also check out [this list of helpful tips](helpful-tips.html).
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 arranged, 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]()/.
+Don't like how the template looks? Want to change how things are arranged, 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](customization.html).
diff --git a/docs/images/endpoint-auth.png b/docs/images/endpoint-auth.png
new file mode 100644
index 00000000..a72523d2
Binary files /dev/null and b/docs/images/endpoint-auth.png differ
diff --git a/docs/images/endpoint-groups.png b/docs/images/endpoint-groups.png
new file mode 100644
index 00000000..986397e2
Binary files /dev/null and b/docs/images/endpoint-groups.png differ
diff --git a/docs/images/endpoint-queryparams-1.png b/docs/images/endpoint-queryparams-1.png
new file mode 100644
index 00000000..e4a326f9
Binary files /dev/null and b/docs/images/endpoint-queryparams-1.png differ
diff --git a/docs/images/endpoint-queryparams-2.png b/docs/images/endpoint-queryparams-2.png
new file mode 100644
index 00000000..2f6b1fa7
Binary files /dev/null and b/docs/images/endpoint-queryparams-2.png differ
diff --git a/docs/images/endpoint-queryparams-3.png b/docs/images/endpoint-queryparams-3.png
new file mode 100644
index 00000000..47cf295b
Binary files /dev/null and b/docs/images/endpoint-queryparams-3.png differ
diff --git a/docs/images/endpoint-title-description.png b/docs/images/endpoint-title-description.png
new file mode 100644
index 00000000..6ee75db0
Binary files /dev/null and b/docs/images/endpoint-title-description.png differ
diff --git a/docs/images/endpoint-urlparams-1.png b/docs/images/endpoint-urlparams-1.png
new file mode 100644
index 00000000..1d689cad
Binary files /dev/null and b/docs/images/endpoint-urlparams-1.png differ
diff --git a/docs/images/endpoint-urlparams-2.png b/docs/images/endpoint-urlparams-2.png
new file mode 100644
index 00000000..48b70cce
Binary files /dev/null and b/docs/images/endpoint-urlparams-2.png differ
diff --git a/docs/index.md b/docs/index.md
index 2c3580bb..4205f6ac 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -8,9 +8,15 @@ Generate API documentation for humans from your Laravel/Lumen/[Dingo](https://gi
* [Getting started](guide-getting-started.md)
* [Whats new](whats-new.md)
* [Migrating from mpociot/laravel-apidoc-generator](migrating.md)
-* [Configuration](config.md)
-* [Generating Documentation](generating-documentation.md)
* [Documenting Your API](documenting.md)
+ * [Adding general information about your API](documenting-api-information.md)
+ * [Specifying metadata about an endpoint](documenting-endpoint-metadata.md)
+ * [Headers to be sent in requests to the endpoint](documenting-endpoint-headers.md)
+ * [Query parameters and URL parameters to be sent in requests to the endpoint](documenting-endpoint-query-parameters.md)
+ * [Body parameters and files to be sent in requests to the endpoint](documenting-endpoint-body-parameters.md)
+ * [Example responses returned from the endpoint](documenting-endpoint-responses.md)
+* [Generating Documentation](generating-documentation.md)
+* [Configuration](config.md)
* [Helpful Tips](helpful-tips.md)
* [Troubleshooting and Debugging](troubleshooting.md)
* [Advanced Customization](customization.md)
diff --git a/docs/migrating.md b/docs/migrating.md
index 82cc9cbf..111d0c44 100644
--- a/docs/migrating.md
+++ b/docs/migrating.md
@@ -33,6 +33,7 @@ _After you've done all of the above_, delete your `resources/docs/` and `public/
## Key changes
### High impact
+- The `postman.name` key has been removed instead. Use the `title` key, which will set both Postman collection name and the generated doc's HTMl title.
- The `laravel.autoload` key is now `laravel.add_routes`, and is `true` by default.
- The `laravel.docs_url` key is now `/docs` by default (no longer `/doc`). This means if you're using `laravel` 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 in `resources/docs/groups` and are split by groups (1 group per file).
diff --git a/docs/plugins.md b/docs/plugins.md
index 6f14853e..5803eb74 100644
--- a/docs/plugins.md
+++ b/docs/plugins.md
@@ -1,4 +1,6 @@
# Extending functionality with plugins
+[IN PROGRESS]
+
You can use plugins to alter how the Generator fetches data about your routes. For instance, suppose all your routes have a body parameter `organizationId`, and you don't want to annotate this with `@queryParam` on each method. You can create a plugin that adds this to all your body parameters. Let's see how to do this.
## The stages of route processing
diff --git a/logo-scribe.png b/logo-scribe.png
new file mode 100644
index 00000000..e17ab830
Binary files /dev/null and b/logo-scribe.png differ
diff --git a/resources/views/partials/route.blade.php b/resources/views/partials/route.blade.php
index 5477e0f7..c22b6c51 100644
--- a/resources/views/partials/route.blade.php
+++ b/resources/views/partials/route.blade.php
@@ -1,4 +1,5 @@
## {{ $route['metadata']['title'] ?: $route['uri']}}
+
@component('scribe::components.badges.auth', ['authenticated' => $route['metadata']['authenticated']])
@endcomponent
diff --git a/src/Writing/PostmanCollectionWriter.php b/src/Writing/PostmanCollectionWriter.php
index d688014b..8ecfc414 100644
--- a/src/Writing/PostmanCollectionWriter.php
+++ b/src/Writing/PostmanCollectionWriter.php
@@ -48,7 +48,7 @@ public function getCollection()
$collection = [
'variables' => [],
'info' => [
- 'name' => config('scribe.postman.name') ?: config('app.name') . ' API',
+ 'name' => config('scribe.title') ?: config('app.name') . ' API',
'_postman_id' => Uuid::uuid4()->toString(),
'description' => config('scribe.postman.description') ?: '',
'schema' => 'https://schema.getpostman.com/json/collection/v2.0.0/collection.json',
diff --git a/src/Writing/Writer.php b/src/Writing/Writer.php
index dded8ec1..f442f180 100644
--- a/src/Writing/Writer.php
+++ b/src/Writing/Writer.php
@@ -103,7 +103,7 @@ public function writeMarkdownAndSourceFiles(Collection $parsedRoutes)
$settings = [
'languages' => $this->config->get('example_languages'),
'logo' => $this->config->get('logo'),
- 'title' => config('app.name', '') . ' API Documentation',
+ 'title' => $this->config->get('title', config('app.name', '') . ' API Documentation'),
];
ConsoleOutputUtils::info('Writing source Markdown files to: ' . $this->sourceOutputPath);
diff --git a/todo.md b/todo.md
index ee8876f0..ca8b1c5e 100644
--- a/todo.md
+++ b/todo.md
@@ -7,13 +7,14 @@
- plugin api: responses - description, $stage property, scribe:strategy
- --env
- Use database transactions and `create()` when instantiating factory models
+ - fileParams
# Release blocker
- Port recent changes from old repo
-# Improvements
-- Speed
-
# Features
- Possible feature: https://github.com/mpociot/laravel-apidoc-generator/issues/731
+# Fixes
+- When groups are removed, the markdown files persist, so they remain in the doc
+