API
The API is intended for developers who need to call Convert-Pheno from another application. Most users should use the command-line interface.
In some cases it is more convenient to send conversion requests over an HTTP(s) endpoint instead of calling the module directly. For that case, Convert-Pheno includes a lightweight REST API.
Basic requestβ
Send a POST request to /api with a JSON body. Local examples below use plain http:// for simplicity, but the same API can also be exposed over https:// depending on deployment:
curl -d "@data.json" -H 'Content-Type: application/json' -X POST http://localhost:3000/api
Example payload:
{
"conversion": "pxf2bff",
"input": {
"data": { "...": "..." }
},
"output": {
"entities": ["individuals"]
},
"options": {
"ohdsi_db": false
}
}
The response is a JSON envelope with ok, data, and meta.conversion.
The HTTP(s) boundary accepts in-memory payloads, not paths on the API host.
input may contain data; output may contain entities and
derived_entity_overrides. Safe conversion settings belong under options.
File-bearing fields such as in_file, out_file, mapping_file,
redcap_dictionary, define_xml, and path_to_ohdsi_db are rejected.
OMOP table dataβ
For omop2bff and omop2pxf, send the OMOP rows under input.data, keyed by
table name. Each table contains an array of row objects:
{
"conversion": "omop2bff",
"input": {
"data": {
"CONCEPT": [{
"concept_id": 8532,
"concept_name": "FEMALE",
"concept_code": "F",
"vocabulary_id": "Gender"
}],
"PERSON": [{ "person_id": 974, "gender_concept_id": 8532 }]
}
}
}
CONCEPT and PERSON must be included. The client does not group records by
patient: Convert-Pheno builds the concept caches and groups rows by person_id
before applying the same mapping used for file-based OMOP input. Large OMOP
datasets remain better suited to the CLI streaming mode because HTTP(s)
requests are processed in memory.
Accepted option fields
default_vital_status, levenshtein_weight, max_lines_sql,
min_text_similarity_score, ohdsi_db, omop_tables,
search, source_info, test, text_similarity_method, and username.
OpenAPI specification
The source schema for the Perl/Mojolicious wrapper lives in api/perl/openapi.json. A rendered OpenAPI reference is also available as Redoc.
JavaScript usageβ
The REST API is language-agnostic. JavaScript clients can call the same /api endpoint with the same JSON request body.
- Browser fetch
- Node.js fetch
async function run() {
const payload = {
conversion: "pxf2bff",
input: {
data: {
subject: {
id: "P0007500",
sex: "FEMALE"
}
}
},
output: {
entities: ["individuals"]
},
options: {
test: true
}
};
const response = await fetch("http://localhost:3000/api", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
const result = await response.json();
if (!result.ok) {
console.error(result.error);
} else {
console.log(result.data);
}
}
run();
This browser example assumes the API is same-origin with the page, or that the deployment enables CORS.
async function run() {
const payload = {
conversion: "pxf2bff",
input: {
data: {
subject: {
id: "P0007500",
sex: "FEMALE"
}
}
},
output: {
entities: ["individuals"]
},
options: {
test: true
}
};
const response = await fetch("http://localhost:3000/api", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
const result = await response.json();
if (!result.ok) {
throw new Error(result.error.message);
}
console.log(result.meta.conversion);
console.log(result.data);
}
run().catch(console.error);
Node.js 21+ includes stable built-in fetch. Older Node.js versions may require a polyfill such as undici.
Recommended API routesβ
The REST API works best for self-contained payloads where the request already carries the data needed for conversion.
| Input family | REST API status | Why |
|---|---|---|
BFF | Recommended | Small JSON payloads are natural to send over HTTP(s) |
PXF | Recommended | Small JSON payloads are natural to send over HTTP(s) |
OMOP-CDM | Recommended with care | Send table rows as JSON; Convert-Pheno groups them by patient in memory |
FHIR R4 / mCODE 4.0 | Available | A self-contained JSON Bundle can be sent directly as input.data; mCODE profiles are detected automatically |
openEHR | Available | Canonical JSON/YAML content can be sent directly as input.data |
CSV | CLI/module only | Mapping-file conversion depends on file artifacts that are not accepted by the HTTP boundary |
REDCap | CLI/module only | Requires project data, a REDCap dictionary, and mapping-file context |
CDISC-ODM | CLI/module only | Requires XML plus a mapping file; only REDCap-origin ODM also uses an external dictionary |
CDISC Dataset-JSON | CLI/module only | Accepts multiple SDTM domain documents that are grouped before conversion |
CDISC Dataset-XML | CLI/module only | Requires Dataset-XML documents plus accompanying Define-XML metadata |
For CSV, REDCap, CDISC-ODM, Dataset-JSON, and Dataset-XML, use the CLI or module
interface. The HTTP wrappers reject those file-based routes rather than
accepting server-local paths.
Available implementationsβ
Both server implementations expose the same POST /api contract. Choose the
one that fits the surrounding application stack.
- Perl
- Python
The Mojolicious implementation calls Convert::Pheno directly and serves on
port 3000 by default:
cd api/perl
morbo main.pl
See the Perl API setup.
The FastAPI implementation calls the same Perl conversion layer through the
internal JSON bridge and serves on port 8000 by default:
cd api/python
uvicorn main:app --reload
See the Python API setup.
Client applications in JavaScript can consume the same REST API without needing a dedicated JavaScript server wrapper.
Deployment noteβ
This API is intended to run on a machine where Convert-Pheno and its dependencies are already installed. In practice, the containerized setup is the easiest way to expose it as a local service. The Perl/Mojolicious wrapper is configured for HTTPS when run with hypnotoad, while the Python/FastAPI wrapper is typically served over HTTP(s) in local uvicorn examples depending on whether TLS is configured directly or terminated upstream.
See: