thephpleague/openapi-psr7-validator

repository·master·Indexed 20 days ago

https://github.com/thephpleague/openapi-psr7-validator

A PHP library for validating PSR-7 HTTP requests and responses against OpenAPI 3.0.x specifications. It supports standard and optimized routed validation and can be integrated as PSR-15 or Slim Framework middleware. The library provides tools for loading schemas via ValidatorBuilder, handling validation exceptions, parsing path parameters with OperationAddress, and registering custom OpenAPI type formats.

Tokens
6.2K
Snippets
23
Records
26
Agent score
69%

What's inside openapi-psr7-validator

  1. How to validate a Request message

    master

    To validate a generic \Psr\Http\Message\RequestInterface (not necessarily a ServerRequest), use getRequestValidator() from the ValidatorBuilder.

    $jsonFile = "api.json";
    $validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromJsonFile($jsonFile)->getRequestValidator();
    
    $match = $validator->validate($request);
  2. How to validate a ServerRequest message

    master

    You can validate a \Psr\Http\Message\ServerRequestInterface instance using the ValidatorBuilder. The builder supports loading specifications from YAML files, YAML strings, JSON files, JSON strings, or a pre-generated \cebe\openapi\spec\OpenApi schema object.

    If you already have routing information and know the specific operation (path and method) that should match the request, use getRoutedRequestValidator with an OperationAddress. This is more performant as it avoids searching the entire specification for a match.

    $yamlFile = "api.yaml";
    $validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromYamlFile($yamlFile)->getServerRequestValidator();
    
    // Standard validation (returns OperationAddress match)
    $match = $validator->validate($request);
    
    // Optimized validation using known routing
    $address = new \League\OpenAPIValidation\PSR7\OperationAddress('/some/operation', 'post');
    $validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromSchema($schema)->getRoutedRequestValidator();
    $validator->validate($address, $request);
  3. Use OpenAPI validation as PSR-15 Middleware

    master

    You can integrate validation into your PSR-15 compatible middleware stack using the ValidationMiddlewareBuilder.

    $yamlFile = 'api.yaml';
    $psr15Middleware = (new \League\OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromYamlFile($yamlFile)->getValidationMiddleware();
  4. How to validate a Response message

    master

    Validating a \Psr\Http\Message\ResponseInterface requires an OperationAddress because the validator must know which OpenAPI operation the response is expected to satisfy (to check status codes, content types, etc.).

    $yamlFile = "api.yaml";
    $validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromYamlFile($yamlFile)->getResponseValidator();
    
    // You must provide the operation context
    $operation = new \League\OpenAPIValidation\PSR7\OperationAddress('/password/gen', 'get');
    
    $validator->validate($operation, $response);
  5. Use OpenAPI validation with Slim Framework

    master

    Since Slim uses a slightly different middleware interface, use the SlimAdapter to wrap a PSR-15 validation middleware.

    $yamlFile = 'api.yaml';
    $psr15Middleware = (new \League\OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)->fromYamlFile($yamlFile)->getValidationMiddleware();
    
    $slimMiddleware = new \League\OpenAPIValidation\PSR15\SlimAdapter($psr15Middleware);
    
    /** @var \Slim\App $app */
    $app->add($slimMiddleware);
  6. Configure PSR-6 caching for the validator

    master

    To improve performance by reducing the time spent parsing OpenAPI specifications, you can enable an optional caching layer using any PSR-6 compliant cache pool.

    You can set the cache via setCache($pool, $ttl) where $ttl is the expiration time in seconds (or null). You can also use overrideCacheKey('my_custom_key') if you need to control the cache key used for the schema.

    // Configure a PSR-6 Cache Pool
    $cachePool = new ArrayCachePool();
    
    // Pass it to the PSR-7 builder
    $validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)
        ->fromYamlFile($yamlFile)
        ->setCache($cachePool)
        ->getResponseValidator();
    
    // Or pass it to the PSR-15 builder
    $psr15Middleware = (new \League\OpenAPIValidation\PSR15\ValidationMiddlewareBuilder)
        ->fromYamlFile($yamlFile)
        ->setCache($cachePool)
        ->getValidationMiddleware();
  7. How BreadCrumb identifies data structure paths

    master

    The BreadCrumb class is used to represent a specific path within a complex data structure (like a nested JSON object or array) to help identify exactly where a validation error occurred. It works as a linked list of indices or keys. You can build a chain of crumbs to represent a path, and then use buildChain() to resolve that path into a flat array of keys/indices.

    use League\OpenAPIValidation\Schema\BreadCrumb;
    
    // Start at the root
    $root = new BreadCrumb();
    
    // Navigate into an object key 'user', then an array index 0, then a key 'name'
    $path = $root->addCrumb('user')
                 ->addCrumb(0)
                 ->addCrumb('name');
    
    // Resolve the path to an array of keys
    $keys = $path->buildChain();
    // Result: ['user', 0, 'name']
  8. Reuse the OpenAPI schema after validation

    master

    The ValidatorBuilder compiles the OpenAPI specification into an instance of \cebe\openapi\spec\OpenApi. You can retrieve this instance using getSchema() to avoid re-parsing the specification if you need to perform other operations with the schema object.

    $validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)->fromYamlFile($yamlFile)->getServerRequestValidator();
    
    /** @var \cebe\openapi\spec\OpenApi */
    $openApi = $validator->getSchema();
  9. Register custom type formats

    master

    The package includes built-in format validators for types like email, uuid, ipv4, etc. You can extend this by registering your own custom format validators. A format validator must be a callable that returns true if the format matches the data, and false otherwise.

    // Register a custom format using a closure
    \League\OpenAPIValidation\Schema\TypeFormats\FormatsContainer::registerFormat('string', 'custom', function ($value): bool {
        return $value === "good value";
    });
    
    // Or using a callable class
    $customFormat = new class {
        public function __invoke($value): bool {
            return $value === "good value";
        }
    };
    \League\OpenAPIValidation\Schema\TypeFormats\FormatsContainer::registerFormat('string', 'custom', $customFormat);
  10. Validate standalone data against an OpenAPI schema

    master

    If you need to validate raw data against a specific schema without the context of an HTTP message, use the SchemaValidator class.

    use League\OpenAPIValidation\Schema\SchemaValidator;
    use cebe\openapi\Reader;
    
    $specYaml = "schema:\n  type: string\n  enum:\n  - a\n  - b";
    $data = "c";
    
    $spec = Reader::readFromYaml($specYaml);
    $schema = new \cebe\openapi\spec\Schema($spec->schema);
    
    try {
        (new SchemaValidator())->validate($data, $schema);
    } catch(\League\OpenAPIValidation\Schema\Exception\KeywordMismatch $e) {
        // $e->keyword() returns the failed keyword (e.g., 'enum')
        // $e->data() returns the invalid data (e.g., 'c')
    }