> ## Documentation Index
> Fetch the complete documentation index at: https://geni.masiting.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Form Requests & Validation

> Static validation rule extraction from Form Requests, Validator::make, and inline validate() calls.

## Overview

Geni automatically documents request body schemas by statically analyzing validation rules in your code. You never need to duplicate validation rules in docblock comments.

## Supported Validation Sources

Geni inspects three distinct validation sources:

### 1. Dedicated Form Requests (Recommended)

When a controller action parameter type-hints a class extending `Illuminate\Foundation\Http\FormRequest`:

```php theme={null}
public function store(StoreArticleRequest $request)
{
    // ...
}
```

Geni resolves the `StoreArticleRequest` class and parses the array returned by its `rules()` method:

```php theme={null}
class StoreArticleRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'title' => ['required', 'string', 'max:120'],
            'body' => ['required', 'string'],
            'status' => ['nullable', Rule::in(['draft', 'published', 'archived'])],
            'tags' => ['array'],
            'tags.*' => ['integer', 'exists:tags,id'],
            'cover_image' => ['nullable', 'image', 'max:2048'],
        ];
    }
}
```

### 2. Inline `$request->validate()`

When validation is performed directly inside the controller method:

```php theme={null}
public function store(Request $request)
{
    $validated = $request->validate([
        'title' => 'required|string|max:120',
        'category_id' => 'required|integer',
    ]);
}
```

### 3. `Validator::make()`

When using the `Validator` facade or helper:

```php theme={null}
public function update(Request $request, Post $post)
{
    $validator = Validator::make($request->all(), [
        'title' => 'required|string',
    ]);
}
```

## Validation Rule Mapping Table

| Laravel Rule                    | OpenAPI JSON Schema Property                                    |
| ------------------------------- | --------------------------------------------------------------- |
| `required`                      | Added to schema `required` array                                |
| `nullable`                      | Omitted from `required`; supports `type: [type, "null"]`        |
| `string`, `alpha`, `alpha_dash` | `type: "string"`                                                |
| `integer`, `numeric`, `digits`  | `type: "integer"` or `type: "number"`                           |
| `boolean`                       | `type: "boolean"`                                               |
| `array`                         | `type: "array"`                                                 |
| `date`, `date_format:Y-m-d`     | `type: "string"`, `format: "date"`                              |
| `date_format:Y-m-d H:i:s`       | `type: "string"`, `format: "date-time"`                         |
| `email`                         | `type: "string"`, `format: "email"`                             |
| `url`, `active_url`             | `type: "string"`, `format: "uri"`                               |
| `uuid`                          | `type: "string"`, `format: "uuid"`                              |
| `min:val`                       | `minLength: val` (string) or `minimum: val` (numeric)           |
| `max:val`                       | `maxLength: val` (string) or `maximum: val` (numeric)           |
| `between:min,max`               | `minLength` / `maxLength` or `minimum` / `maximum`              |
| `in:a,b,c` / `Rule::in(...)`    | `enum: ["a", "b", "c"]`                                         |
| `file`, `image`, `mimes:...`    | `format: "binary"`; switches request to `multipart/form-data`   |
| `confirmed`                     | Automatically generates sibling `{field}_confirmation` property |

## Multipart Form Data Detection

When Geni detects a `file`, `image`, or `mimes` rule on any field in a request, it automatically sets the request body media type to `multipart/form-data` instead of `application/json`.
