# adp-api-transformer

A CLI tool that transforms OpenAPI specifications (JSON or YAML) for use in the ADP1 APIM repository. It enriches specs with missing attributes, normalizes operation metadata, and can split large specs into smaller per-tag or per-path files — each containing only the relevant paths and schemas.

## Table of Contents

- [Features](#features)
- [Installation](#installation)
- [Usage](#usage)
  - [Basic conversion](#basic-conversion)
  - [Split by tag](#split-by-tag)
  - [Split by path](#split-by-path)
- [What the tool does](#what-the-tool-does)
  - [Attribute enrichment](#attribute-enrichment)
  - [Schema filtering](#schema-filtering)
  - [Path rewriting](#path-rewriting)
- [Examples](#examples)
- [Requirements](#requirements)
- [Building and publishing](#building-and-publishing)

## Features

- Accepts OpenAPI specs in `.json`, `.yaml`, or `.yml` formats.
- Adds missing `operationId`, `summary`, and `tags` fields to every operation.
- Ensures every `operationId` ends with the `-{{consumerphase}}` suffix (appends it if missing).
- Sets `info.title` to the template value `{{apiTitle}}`.
- **Split by tag** — produces one file per tag, with paths starting after the tag segment.
- **Split by path** — groups endpoints by their first path segment, with an optional prefix to ignore (e.g. `api/v1`).
- Only includes schemas that are actually referenced by each split file (plus general shared schemas), resolved recursively.
- Outputs all specs as formatted JSON.

## Installation

### From PyPI

```sh
pip install adp-api-transformer
```

### For development

Clone the repository and install in editable mode:

```sh
git clone <repo-url>
cd adp-api-converter
pip install -e .
```

## Usage

```
adp-api-transformer <input_file> [output] [--split-by-tag] [--split-by-path] [--ignore-prefix PREFIX]
```

| Argument | Description |
|---|---|
| `input_file` | Path to the input OpenAPI spec (JSON or YAML). **Required.** |
| `output` | Output file path (single-file mode) or ignored when splitting. Defaults to `openapi.json`. |
| `--split-by-tag` | Split the spec into multiple files based on each operation's first tag. |
| `--split-by-path` | Split the spec into multiple files based on the first path segment. |
| `--ignore-prefix PREFIX` | Used with `--split-by-path`. Strips this prefix before determining the grouping segment (e.g. `api/v1`). |

> When using `--split-by-tag` or `--split-by-path`, output files are written to a directory named after the input file (without the extension).

---

### Basic conversion

Convert a spec and write a single enriched JSON file:

```sh
adp-api-transformer api.yaml modified_api.json
```

### Split by tag

Create one file per tag. Each file only contains the operations for that tag, with paths rewritten to start after the tag segment:

```sh
adp-api-transformer api.yaml --split-by-tag
```

Given an input with paths `/collection`, `/collection/{id}`, and `/user/profile`, this produces:

```
api/
  collection.openapi.json   # paths: /  and /{id}
  user.openapi.json          # paths: /profile
```

### Split by path

Group endpoints by the first meaningful path segment. Useful when tags are absent or unreliable:

```sh
adp-api-transformer api.yaml --split-by-path
```

If your paths share a common prefix (e.g. `/api/v1/studies/...`, `/api/v1/extractions/...`), use `--ignore-prefix` so grouping happens on the segment *after* the prefix:

```sh
adp-api-transformer api.yaml --split-by-path --ignore-prefix api/v1
```

This groups `/api/v1/studies/{id}` under **studies** (path becomes `/{id}`) and `/api/v1/extractions` under **extractions** (path becomes `/`).

## What the tool does

### Attribute enrichment

Every operation in the spec is processed with the following rules:

| Field | Rule |
|---|---|
| `info.title` | Always set to `{{apiTitle}}`. |
| `operationId` | If missing or empty, generated as `<method>_<path>-{{consumerphase}}` (e.g. `get_collection_id-{{consumerphase}}`). If present but not ending with `-{{consumerphase}}`, the suffix is appended. |
| `summary` | If missing, generated as `<METHOD> <path>` (e.g. `GET /collection/{id}`). |
| `tags` | If missing or empty, set to the first path segment (e.g. `/collection/{id}` → `["collection"]`). |

### Schema filtering

When splitting, each output file only includes:

1. **Directly referenced schemas** — any `$ref` pointing to `#/components/schemas/...` found in that file's operations.
2. **Transitively referenced schemas** — if schema A references schema B, both are included.
3. **General shared schemas** — schemas named `security`, `error`, `paginated`, or `metadata` are always included (if they exist).
4. **Other component types** — `securitySchemes` are copied to every output file. Other top-level fields (e.g. `servers`, `security`) are also preserved.

### Path rewriting

| Mode | Input path | Result |
|---|---|---|
| **Split by tag** (tag = `collection`) | `/collection/{id}` | `/{id}` |
| **Split by tag** (tag = `collection`) | `/collection` | `/` |
| **Split by path** | `/studies/{id}/results` | Group: `studies`, path: `/{id}/results` |
| **Split by path** with `--ignore-prefix api/v1` | `/api/v1/studies/{id}` | Group: `studies`, path: `/{id}` |

## Examples

The `example/` directory contains sample output files generated by splitting the included `example.openapi.json` by tag:

```
example/
  collection.openapi.json
  domain.openapi.json
  user.openapi.json
  workflow.openapi.json
  ...
```

To regenerate them:

```sh
adp-api-transformer example.openapi.json --split-by-tag
```

## Requirements

- Python 3.9+
- [pyyaml](https://pypi.org/project/PyYAML/)