# Extending the CLI

> Register custom exporters and importers to add new output and input formats to the Data Contract CLI.

The CLI uses factory patterns for export and import, so you can register your own **custom exporter** (a new output format) or **custom importer** (a new input format) and use them through the same `DataContract` API.

:::note
For producing a custom text output from a Jinja template, you usually don't need code — use the built-in [`export custom`](./exports/custom.md) exporter. Register a custom exporter class (below) when you need full programmatic control.
:::

## Custom exporter

Implement `Exporter.export(...)` and register the class with the exporter factory. The `data_contract` argument is an `OpenDataContractStandard` (ODCS) instance, so you read `data_contract.name`, `data_contract.version`, `data_contract.schema_`, etc.

```python
from datacontract.data_contract import DataContract
from datacontract.export.exporter import Exporter
from datacontract.export.exporter_factory import exporter_factory

class MyExporter(Exporter):
    def export(self, data_contract, schema_name, server, sql_server_type, export_args) -> str:
        lines = [f"# {data_contract.name} v{data_contract.version}"]
        for schema in data_contract.schema_ or []:
            columns = ", ".join(p.name for p in (schema.properties or []))
            lines.append(f"{schema.name}: {columns}")
        return "\n".join(lines)

# Register the exporter under a new format name
exporter_factory.register_exporter("my_format", MyExporter)

# Use it like any built-in format
data_contract = DataContract(data_contract_file="datacontract.yaml")
print(data_contract.export("my_format"))
```

The `export()` method receives:

| Argument | Description |
|---|---|
| `data_contract` | The contract as an `OpenDataContractStandard` object. |
| `schema_name` | The selected schema, or `"all"`. |
| `server` | The selected server name (or `None`). |
| `sql_server_type` | The SQL dialect (`"auto"` by default). |
| `export_args` | A dict of any extra keyword arguments passed to `export(...)`. |

## Custom importer

Implement `Importer.import_source(...)` to build and return an `OpenDataContractStandard`, then register it with the importer factory.

```python
import json
from open_data_contract_standard.model import (
    OpenDataContractStandard,
    SchemaObject,
    SchemaProperty,
)
from datacontract.data_contract import DataContract
from datacontract.imports.importer import Importer
from datacontract.imports.importer_factory import importer_factory

class MyImporter(Importer):
    def import_source(self, source, import_args) -> OpenDataContractStandard:
        data = json.loads(source)
        return OpenDataContractStandard(
            apiVersion="v3.0.2",
            kind="DataContract",
            id=data["id"],
            name=data["title"],
            version=data["version"],
            description={"purpose": data.get("description")},
            schema=[
                SchemaObject(
                    name=model["name"],
                    properties=[
                        SchemaProperty(name=col["name"], logicalType=col.get("type"))
                        for col in model["columns"]
                    ],
                )
                for model in data.get("models", [])
            ],
        )

# Register the importer under a new format name
importer_factory.register_importer("my_format", MyImporter)

source = '{"id": "urn:my:contract", "title": "My Contract", "version": "1.0.0", "models": []}'
odcs = DataContract.import_from_source(format="my_format", source=source)

# import_from_source returns an ODCS object; wrap it to export or test
print(DataContract(data_contract=odcs).export("odcs"))
```

## Tips

- Register classes once at import time (e.g. in a small plugin module you import before using the CLI as a library).
- Custom formats are only available through the [Python library](./python-library.md), not the standalone `datacontract` command.
- See the built-in exporters/importers in the [source tree](https://github.com/datacontract/datacontract-cli/tree/main/datacontract) for complete, real-world implementations.
