Files
gh-epieczko-betty/skills/api.validate/SKILL.md
2025-11-29 18:26:08 +08:00

316 lines
7.7 KiB
Markdown

# api.validate
## Overview
**api.validate** validates OpenAPI and AsyncAPI specifications against enterprise guidelines, with built-in support for Zalando RESTful API Guidelines.
## Purpose
Ensure API specifications meet enterprise standards:
- Validate OpenAPI 3.x specifications
- Validate AsyncAPI 3.x specifications
- Check compliance with Zalando guidelines
- Detect common API design mistakes
- Provide actionable suggestions for fixes
## Usage
### Basic Usage
```bash
python skills/api.validate/api_validate.py <spec_path> [guideline_set] [options]
```
### Parameters
| Parameter | Required | Description | Default |
|-----------|----------|-------------|---------|
| `spec_path` | Yes | Path to API spec file | - |
| `guideline_set` | No | Guidelines to validate against | `zalando` |
| `--strict` | No | Warnings become errors | `false` |
| `--format` | No | Output format (json, human) | `json` |
### Guideline Sets
| Guideline | Status | Description |
|-----------|--------|-------------|
| `zalando` | ✅ Supported | Zalando RESTful API Guidelines |
| `google` | 🚧 Planned | Google API Design Guide |
| `microsoft` | 🚧 Planned | Microsoft REST API Guidelines |
## Examples
### Example 1: Validate OpenAPI Spec
```bash
python skills/api.validate/api_validate.py specs/user-service.openapi.yaml zalando
```
**Output** (JSON format):
```json
{
"status": "success",
"data": {
"valid": false,
"errors": [
{
"rule_id": "MUST_001",
"message": "Missing required field 'info.x-api-id'",
"severity": "error",
"path": "info.x-api-id",
"suggestion": "Add a UUID to uniquely identify this API"
}
],
"warnings": [
{
"rule_id": "SHOULD_001",
"message": "Missing 'info.contact'",
"severity": "warning",
"path": "info.contact"
}
],
"spec_path": "specs/user-service.openapi.yaml",
"spec_type": "openapi",
"guideline_set": "zalando"
}
}
```
### Example 2: Human-Readable Output
```bash
python skills/api.validate/api_validate.py \
specs/user-service.openapi.yaml \
zalando \
--format=human
```
**Output**:
```
============================================================
API Validation Report
============================================================
Spec: specs/user-service.openapi.yaml
Type: OPENAPI
Guidelines: zalando
============================================================
❌ ERRORS (1):
[MUST_001] Missing required field 'info.x-api-id'
Path: info.x-api-id
💡 Add a UUID to uniquely identify this API
⚠️ WARNINGS (1):
[SHOULD_001] Missing 'info.contact'
Path: info.contact
💡 Add contact information
============================================================
❌ Validation FAILED
============================================================
```
### Example 3: Strict Mode
```bash
python skills/api.validate/api_validate.py \
specs/user-service.openapi.yaml \
zalando \
--strict
```
In strict mode, warnings are treated as errors. Use for CI/CD pipelines where you want zero tolerance for issues.
### Example 4: Validate AsyncAPI Spec
```bash
python skills/api.validate/api_validate.py specs/user-events.asyncapi.yaml
```
## Validation Rules
### Zalando Guidelines (OpenAPI)
#### MUST Rules (Errors)
| Rule | Description | Example Fix |
|------|-------------|-------------|
| **MUST_001** | Required `x-api-id` metadata | `x-api-id: 'd0184f38-b98d-11e7-9c56-68f728c1ba70'` |
| **MUST_002** | Required `x-audience` metadata | `x-audience: 'company-internal'` |
| **MUST_003** | Path naming conventions | Use lowercase kebab-case or snake_case |
| **MUST_004** | Property naming (snake_case) | `userId``user_id` |
| **MUST_005** | HTTP method usage | GET should not have requestBody |
#### SHOULD Rules (Warnings)
| Rule | Description | Example Fix |
|------|-------------|-------------|
| **SHOULD_001** | Contact information | Add `info.contact` with team details |
| **SHOULD_002** | POST returns 201 | Add 201 response to POST operations |
| **SHOULD_003** | Document 400 errors | Add 400 Bad Request response |
| **SHOULD_004** | Document 500 errors | Add 500 Internal Error response |
| **SHOULD_005** | 201 includes Location header | Add Location header to 201 responses |
| **SHOULD_006** | Problem schema for errors | Define RFC 7807 Problem schema |
| **SHOULD_007** | Error responses use application/problem+json | Use correct content type |
| **SHOULD_008** | X-Flow-ID header | Add request tracing header |
| **SHOULD_009** | Security schemes defined | Add authentication schemes |
### AsyncAPI Guidelines
| Rule | Description |
|------|-------------|
| **ASYNCAPI_001** | Required `info` field |
| **ASYNCAPI_002** | Required `channels` field |
| **ASYNCAPI_003** | Version check (recommend 3.x) |
## Integration with Hooks
### Automatic Validation on File Edit
```bash
# Create hook using hook.define
python skills/hook.define/hook_define.py \
on_file_edit \
"python betty/skills/api.validate/api_validate.py {file_path} zalando" \
--pattern="*.openapi.yaml" \
--blocking=true \
--timeout=10000 \
--description="Validate OpenAPI specs on edit"
```
**Result**: Every time you edit a `*.openapi.yaml` file, it's automatically validated. If validation fails, the edit is blocked.
### Validation on Commit
```bash
python skills/hook.define/hook_define.py \
on_commit \
"python betty/skills/api.validate/api_validate.py {file_path} zalando --strict" \
--pattern="specs/**/*.yaml" \
--blocking=true \
--description="Prevent commits with invalid specs"
```
## Exit Codes
| Code | Meaning |
|------|---------|
| `0` | Validation passed (no errors) |
| `1` | Validation failed (has errors) or execution error |
## Common Validation Errors
### Missing x-api-id
**Error**:
```
Missing required field 'info.x-api-id'
```
**Fix**:
```yaml
info:
title: My API
version: 1.0.0
x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 # Add this
```
### Wrong Property Naming
**Error**:
```
Property 'userId' should use snake_case
```
**Fix**:
```yaml
# Before
properties:
userId:
type: string
# After
properties:
user_id:
type: string
```
### Missing Error Responses
**Error**:
```
GET operation should document 400 (Bad Request) response
```
**Fix**:
```yaml
responses:
'200':
description: Success
'400': # Add this
$ref: '#/components/responses/BadRequest'
'500': # Add this
$ref: '#/components/responses/InternalError'
```
### Wrong Content Type for Errors
**Error**:
```
Error response 400 should use 'application/problem+json'
```
**Fix**:
```yaml
'400':
description: Bad request
content:
application/problem+json: # Not application/json
schema:
$ref: '#/components/schemas/Problem'
```
## Use in Workflows
```yaml
# workflows/api_validation_suite.yaml
steps:
- skill: api.validate
args:
- "specs/user-service.openapi.yaml"
- "zalando"
- "--strict"
required: true
```
## Dependencies
- **PyYAML**: Required for YAML parsing
```bash
pip install pyyaml
```
## Files
### Input
- `*.openapi.yaml` - OpenAPI 3.x specifications
- `*.asyncapi.yaml` - AsyncAPI 3.x specifications
- `*.json` - JSON format specifications
### Output
- JSON validation report (stdout)
- Human-readable report (with `--format=human`)
## See Also
- [hook.define](../hook.define/SKILL.md) - Create validation hooks
- [api.define](../api.define/SKILL.md) - Create OpenAPI specs
- [Betty Architecture](../../docs/betty-architecture.md) - Five-layer model
- [API-Driven Development](../../docs/api-driven-development.md) - Complete guide
- [Zalando API Guidelines](https://opensource.zalando.com/restful-api-guidelines/)
- [RFC 7807 Problem Details](https://datatracker.ietf.org/doc/html/rfc7807)
## Version
**0.1.0** - Initial implementation with Zalando guidelines support