fortanix / openapi-to-effect

Generate @effect/schema definitions from an OpenAPI document
Mozilla Public License 2.0
12 stars 1 forks source link

When there is a allOf, the $ref are never resolved #2

Open joepjoosten opened 3 months ago

joepjoosten commented 3 months ago

I'm parsing the spec for opensearch (https://github.com/opensearch-project/opensearch-api-specification/releases/download/main-latest/opensearch-openapi.yaml)

To download it, and transform it to json:

curl -L https://github.com/opensearch-project/opensearch-api-specification/releases/download/main-latest/opensearch-openapi.yaml > opensearch-openapi.yaml \
| yq -o=json eval opensearch-openapi.yaml > opensearch-openapi.json

When there is an allOf which has a $ref, it always fails because it can't find the schema.

Error:

Error: Unable to find schema "#/components/schemas/_common:WriteResponseBase"
    at isObjectSchema (file:///.//openapi-to-effect/dist/esm/analysis/GraphAnalyzer.mjs:268:11)
    at file:///.//openapi-to-effect/dist/esm/generation/effSchemGen/schemaGen.mjs:327:27
    at Array.reduce (<anonymous>)
    at generateForSchema (file:///.//openapi-to-effect/dist/esm/generation/effSchemGen/schemaGen.mjs:325:44)
    at generateModule (file:///.//openapi-to-effect/dist/esm/generation/effSchemGen/moduleGen.mjs:28:7)
    at file:///.//openapi-to-effect/dist/esm/openapiToEffect.mjs:106:18
    at generateSchemas (file:///.//openapi-to-effect/dist/esm/openapiToEffect.mjs:111:9)
    at async runGenerator (file:///.//openapi-to-effect/dist/esm/openapiToEffect.mjs:405:5)
    at async file:///.//openapi-to-effect/dist/esm/openapiToEffect.mjs:473:9
    at async run (file:///.//openapi-to-effect/dist/esm/openapiToEffect.mjs:459:3)

Looks like the isObjectSchema function in GraphAnalyzer.ts is always empty

mkrause commented 3 months ago

@joepjoosten Tracked it down to this FIXME:

https://github.com/fortanix/openapi-to-effect/blob/eba7d040828456e584dd7f54aa2c7f37fad13039/src/generation/effSchemGen/moduleGen.ts#L21

export const generateModule = (schemaId: string, schema: OpenApiSchema): string => {
  const generationContext: SchemaGenContext = {
    schemas: {}, // FIXME
    hooks: {},
    isSchemaIdBefore(_schemaId: OpenApiSchemaId) { return true; },
  };

For the default one-file-per-schema it doesn't yet have enough context here to resolve references to other schemas.

However, I went though the opensearch API you posted, and got it working with the single bundle mode, with a few fixes in this PR (tagged as v0.7.1):

https://github.com/fortanix/openapi-to-effect/pull/3

You'd need to pass in the following spec using the --spec option:

export default {
  generationMethod: { method: 'bundled', bundleName: 'opensearch' },
  hooks: {},
  runtime: {},
  modules: {},
};

The output is:

https://gist.github.com/mkrause/b85e025d1fc1b5dd2bd2f4b522af2dae

There's still a number of type errors in the resulting bundle however, which are due to recursive schema references. You can add manual type annotations for these in the spec, like in the example in the README here.

mkrause commented 3 months ago

Adding a whole bunch of manual type declarations is obviously not very convenient, and I'm considering adding some TypeScript type generation for the schemas that have recursive references. Unfortunately it's not always straightforward to find the right type to fix a recursive type reference, hence why it's a manual step currently. But it should be possible to automate most cases.