The libs/converter-openapi/README.md table of supported extension fields disagrees with the actual converter implementation in two places. Both make the README claim more capability than the code delivers, which silently misleads users.
1. x-adc-labels is documented as Path-Level but the schema does not allow it there
The README (table row, current main) lists x-adc-labels as supported at Root Level, Path Level, Operation Level.
The Zod schema only defines x-adc-labels on the root document and on each operation object — there is no entry for it on the path object:
https://github.com/api7/adc/blob/main/libs/converter-openapi/src/schema.ts#L58-L75
paths: z.record(
z.string(),
z.looseObject({
[ExtKey.PLUGINS]: xPluginsSchema,
// [ExtKey.PLUGIN_PREFIX]: ignore
[ExtKey.SERVICE_DEFAULTS]: xDefaults,
[ExtKey.UPSTREAM_DEFAULTS]: xDefaults,
[ExtKey.ROUTE_DEFAULTS]: xDefaults,
get: pathOperationSchema,
put: pathOperationSchema,
// ...
}),
),
The path-level object is z.looseObject so the field passes schema validation silently, but src/index.ts never reads operations[ExtKey.LABELS] when iterating paths — only root (oas[ExtKey.LABELS] at line 44) and operation (operation[ExtKey.LABELS] at line 95) are mapped through. Path-level x-adc-labels is silently dropped at conversion time.
Repro: add x-adc-labels: { foo: bar } directly under a path in any test fixture, run convert, and observe the labels do not appear on any route or service in the output.
2. x-adc-plugins at Path/Operation level is documented as causing a service split, but it does not
The README (table row) says:
Plugin objects at the Path level and Operation level will cause the service to be split, i.e. the sub-level containing the plugin will be included in a new service.
The actual splitting logic in src/parser.ts only triggers parseSeprateService when one of x-adc-service-defaults, x-adc-upstream-defaults, or a sub-level servers: entry is present:
https://github.com/api7/adc/blob/main/libs/converter-openapi/src/parser.ts#L60-L65
if (
context &&
(context[ExtKey.SERVICE_DEFAULTS] ||
context[ExtKey.UPSTREAM_DEFAULTS] ||
context.servers)
) {
Plugins are absent from that condition. In src/index.ts, plugins at the path and operation level are merged into route.plugins directly (lines 82-85, 102) without invoking parseSeprateService or producing a new service. Test fixtures test/assets/extension-5.yaml and extension-6.yaml confirm this — plugins at every level produce a single service in the output, not multiple.
Suggested README changes
- Remove the Path Level row from
x-adc-labels, leaving only Root and Operation. (If path-level labels should be supported, that's a feature gap in schema.ts and index.ts rather than a README fix.)
- Remove the "will cause the service to be split" sentence from the
x-adc-plugins row description. The "Extension Fields processing logic" section already correctly describes how plugins are attached to routes without mentioning splitting; the table description just needs to match.
Happy to send a PR if helpful — let me know if either of these is actually intended behavior that I'm misreading from the source, in which case the code is the side that needs adjusting.
Context: discovered while writing documentation in api7/docs#1638 and verifying every claim against the source. The two corrections have already landed in the downstream docs; filing here so the upstream README stops misleading the next person.
The
libs/converter-openapi/README.mdtable of supported extension fields disagrees with the actual converter implementation in two places. Both make the README claim more capability than the code delivers, which silently misleads users.1.
x-adc-labelsis documented as Path-Level but the schema does not allow it thereThe README (table row, current
main) listsx-adc-labelsas supported at Root Level, Path Level, Operation Level.The Zod schema only defines
x-adc-labelson the root document and on each operation object — there is no entry for it on the path object:https://github.com/api7/adc/blob/main/libs/converter-openapi/src/schema.ts#L58-L75
The path-level object is
z.looseObjectso the field passes schema validation silently, butsrc/index.tsnever readsoperations[ExtKey.LABELS]when iterating paths — only root (oas[ExtKey.LABELS]at line 44) and operation (operation[ExtKey.LABELS]at line 95) are mapped through. Path-levelx-adc-labelsis silently dropped at conversion time.Repro: add
x-adc-labels: { foo: bar }directly under a path in any test fixture, runconvert, and observe the labels do not appear on any route or service in the output.2.
x-adc-pluginsat Path/Operation level is documented as causing a service split, but it does notThe README (table row) says:
The actual splitting logic in
src/parser.tsonly triggersparseSeprateServicewhen one ofx-adc-service-defaults,x-adc-upstream-defaults, or a sub-levelservers:entry is present:https://github.com/api7/adc/blob/main/libs/converter-openapi/src/parser.ts#L60-L65
Plugins are absent from that condition. In
src/index.ts, plugins at the path and operation level are merged intoroute.pluginsdirectly (lines 82-85, 102) without invokingparseSeprateServiceor producing a new service. Test fixturestest/assets/extension-5.yamlandextension-6.yamlconfirm this — plugins at every level produce a single service in the output, not multiple.Suggested README changes
x-adc-labels, leaving only Root and Operation. (If path-level labels should be supported, that's a feature gap inschema.tsandindex.tsrather than a README fix.)x-adc-pluginsrow description. The "Extension Fields processing logic" section already correctly describes how plugins are attached to routes without mentioning splitting; the table description just needs to match.Happy to send a PR if helpful — let me know if either of these is actually intended behavior that I'm misreading from the source, in which case the code is the side that needs adjusting.
Context: discovered while writing documentation in api7/docs#1638 and verifying every claim against the source. The two corrections have already landed in the downstream docs; filing here so the upstream README stops misleading the next person.