# OpenMetadata Connector Standards

## Architecture: Schema-First

OpenMetadata connectors follow a **schema-first** architecture. One JSON Schema definition cascades through 6 layers:

```
JSON Schema (single source of truth)
    ├── Python Pydantic models     (make generate)
    ├── Java models                (mvn install -pl openmetadata-spec)
    ├── TypeScript types           (yarn parse-schema)
    ├── UI config forms            (RJSF auto-renders from schema)
    ├── API request validation     (server uses Java models)
    └── Test fixtures              (tests import Pydantic models)
```

**Never hand-write config classes.** Define the JSON Schema; everything else is generated.

## Connector Anatomy

Every connector lives at `ingestion/src/metadata/ingestion/source/{service_type}/{name}/` and has:

| File | Purpose | Required |
|------|---------|----------|
| `__init__.py` | Module marker | Always |
| `connection.py` | Create and test connections | Always |
| `metadata.py` | Extract metadata from the source | Always |
| `service_spec.py` | Register connector with the framework | Always |
| `client.py` | REST/SDK client wrapper | Non-database |
| `queries.py` | SQL query templates | Database |
| `lineage.py` | Lineage extraction | If lineage capability |
| `usage.py` | Usage extraction | If usage capability |
| `query_parser.py` | Query log parsing | If lineage or usage |
| `CONNECTOR_CONTEXT.md` | AI implementation brief | Generated by scaffold |

## Service Types

| Service Type | Base Class | Reference |
|---|---|---|
| `database` | `CommonDbSourceService` | `mysql/` |
| `dashboard` | `DashboardServiceSource` | `metabase/` |
| `pipeline` | `PipelineServiceSource` | `airflow/` |
| `messaging` | `MessagingServiceSource` | `kafka/` |
| `mlmodel` | `MlModelServiceSource` | `mlflow/` |
| `storage` | `StorageServiceSource` | `s3/` |
| `search` | `SearchServiceSource` | `elasticsearch/` |
| `api` | `ApiServiceSource` | `rest/` |

## Connection Types (Database Only)

| Type | Base Class | Pattern |
|------|-----------|---------|
| `sqlalchemy` | `BaseConnection[Config, Engine]` | SQLAlchemy dialect + engine |
| `rest_api` | `get_connection()` / `test_connection()` | Custom REST client |
| `sdk_client` | `get_connection()` / `test_connection()` | Vendor SDK wrapper |

Non-database connectors always use `get_connection()` / `test_connection()` functions.

## ServiceSpec System

Every connector declares a `ServiceSpec` in `service_spec.py`:

- **Database**: `DefaultDatabaseSpec(metadata_source_class=..., connection_class=..., lineage_source_class=..., usage_source_class=...)`
- **All others**: `BaseSpec(metadata_source_class=...)`

The framework resolves specs dynamically via: `metadata.ingestion.source.{service_type}.{name}.service_spec.ServiceSpec`

## Registration Checklist

To register a new connector, modify these files:

1. **Service enum**: `openmetadata-spec/.../entity/services/{serviceType}Service.json` — add type to enum + connection `oneOf`
2. **Test connection**: `openmetadata-service/.../testConnections/{serviceType}/{name}.json` — create file
3. **UI utils**: `openmetadata-ui/.../utils/{ServiceType}ServiceUtils.tsx` — import schema + add switch case
4. **Localization**: `openmetadata-ui/.../locale/languages/` — add i18n display name keys

## Code Generation Commands

```bash
source env/bin/activate
make generate                                # Python Pydantic models
mvn clean install -pl openmetadata-spec      # Java models
cd openmetadata-ui/src/main/resources/ui && yarn parse-schema  # UI schemas
make py_format                               # Format Python
mvn spotless:apply                           # Format Java
```
