瀏覽代碼

Add support for specifying example parameters (closes #391)

shalvah 6 年之前
父節點
當前提交
c7e49529af
共有 5 個文件被更改,包括 91 次插入10 次删除
  1. 15 2
      README.md
  2. 1 1
      resources/views/partials/route.blade.php
  3. 59 5
      src/Tools/Generator.php
  4. 4 2
      tests/Fixtures/TestController.php
  5. 12 0
      tests/Unit/GeneratorTestCase.php

+ 15 - 2
README.md

@@ -188,7 +188,7 @@ class UserController extends Controller
 ### Specifying request parameters
 
 To specify a list of valid parameters your API route accepts, use the `@bodyParam` and `@queryParam` annotations.
-- The `@bodyParam` annotation takes the name of the parameter, its type, 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. 
 - The `@queryParam` annotation takes the name of the parameter, an optional "required" label, and then its description
 
 
@@ -222,6 +222,19 @@ They will be included in the generated documentation text and example requests.
 
 ![](body_params.png)
 
+Note: a random value will be used as the value of each parameter 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
+     */
+```
+
 ### Indicating auth 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.
 
@@ -299,7 +312,7 @@ If you don't specify an example response using any of the above means, this pack
 - 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.
 - Parameters in URLs (example: `/users/{user}`, `/orders/{id?}`) will be replaced with '1' by default. You can configure this, however.Put the parameter names (including curly braces and question marks) as the keys and their replacements as the values in the `bindings` key.
 - You can configure environment 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 `env` key.
-- By default, the package will generate dummy values for your documented body and query parameters and send in the request. You can configure what headers and additional query and parameters should be sent when making the request (the `headers`, `query`, and `body` keys respectively).
+- 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 what headers and additional query and parameters should be sent when making the request (the `headers`, `query`, and `body` keys respectively).
 
 
 ### Postman collections

+ 1 - 1
resources/views/partials/route.blade.php

@@ -19,7 +19,7 @@ curl -X {{$route['methods'][0]}} {{$route['methods'][0] == 'GET' ? '-G ' : ''}}"
 @endforeach
 @endif
 @foreach($route['bodyParameters'] as $attribute => $parameter)
-    -d "{{$attribute}}"="{{$parameter['value']}}" @if(! ($loop->last))\
+    -d "{{$attribute}}"="{{$parameter['value'] === false ? "false" : $parameter['value']}}" @if(! ($loop->last))\
 @endif
 @endforeach
 

+ 59 - 5
src/Tools/Generator.php

@@ -101,7 +101,8 @@ class Generator
                 }
 
                 $type = $this->normalizeParameterType($type);
-                $value = $this->generateDummyValue($type);
+                list($description, $example) = $this->parseDescription($description, $type);
+                $value = is_null($example) ? $this->generateDummyValue($type) : $example;
 
                 return [$name => compact('type', 'description', 'required', 'value')];
             })->toArray();
@@ -137,10 +138,11 @@ class Generator
                     $required = trim($required) == 'required' ? true : false;
                 }
 
-                if (str_contains($description, ['number', 'count', 'page'])) {
-                    $value = $this->generateDummyValue('integer');
-                } else {
-                    $value = $this->generateDummyValue('string');
+                list($description, $value) = $this->parseDescription($description, 'string');
+                if (is_null($value)) {
+                    $value = str_contains($description, ['number', 'count', 'page'])
+                        ? $this->generateDummyValue('integer')
+                        : $this->generateDummyValue('string');
                 }
 
                 return [$name => compact('description', 'required', 'value')];
@@ -255,4 +257,56 @@ class Generator
 
         return $fake();
     }
+
+    /**
+     * Allows users to specify an example for the parameter by writing 'Example: the-example',
+     * to be used in example requests and response calls.
+     *
+     * @param string $description
+     * @param string $type The type of the parameter. Used to cast the example provided, if any.
+     *
+     * @return array The description and included example.
+     */
+    private function parseDescription(string $description, string $type)
+    {
+        $example = null;
+        if (preg_match('/(.*)\s+Example:\s*(.*)\s*/', $description, $content)) {
+            $description = $content[1];
+
+            // examples are parsed as strings by default, we need to cast them properly
+            $example = $this->castToType($content[2], $type);
+        }
+
+        return [$description, $example];
+    }
+
+    /**
+     * Cast a value from a string to a specified type.
+     *
+     * @param string $value
+     * @param string $type
+     *
+     * @return mixed
+     */
+    private function castToType(string $value, string $type)
+    {
+        $casts = [
+            'integer' => 'intval',
+            'number' => 'floatval',
+            'float' => 'floatval',
+            'boolean' => 'boolval',
+        ];
+
+        // First, we handle booleans. We can't use a regular cast,
+        //because PHP considers string 'false' as true.
+        if ($value == 'false' && $type == 'boolean') {
+            return false;
+        }
+
+        if (isset($casts[$type])) {
+            return $casts[$type]($value);
+        }
+
+        return $value;
+    }
 }

+ 4 - 2
tests/Fixtures/TestController.php

@@ -34,9 +34,9 @@ class TestController extends Controller
     }
 
     /**
-     * @bodyParam user_id int required The id of the user.
+     * @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.
+     * @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
      * @bodyParam even_more_param array
@@ -48,6 +48,8 @@ class TestController extends Controller
 
     /**
      * @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
      * @queryParam filters  The filters.
      */
     public function withQueryParameters()

+ 12 - 0
tests/Unit/GeneratorTestCase.php

@@ -51,6 +51,7 @@ abstract class GeneratorTestCase extends TestCase
                 'type' => 'integer',
                 'required' => true,
                 'description' => 'The id of the user.',
+                'value' => 9,
             ],
             'room_id' => [
                 'type' => 'string',
@@ -61,6 +62,7 @@ abstract class GeneratorTestCase extends TestCase
                 'type' => 'boolean',
                 'required' => false,
                 'description' => 'Whether to ban the user forever.',
+                'value' => false,
             ],
             'another_one' => [
                 'type' => 'number',
@@ -91,6 +93,16 @@ abstract class GeneratorTestCase extends TestCase
                 'required' => true,
                 'description' => 'The id of the location.',
             ],
+            'user_id' => [
+                'required' => true,
+                'description' => 'The id of the user.',
+                'value' => 'me',
+            ],
+            'page' => [
+                'required' => true,
+                'description' => 'The page number.',
+                'value' => '4',
+            ],
             'filters' => [
                 'required' => false,
                 'description' => 'The filters.',