Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support replacing types with custom ones when transforming the input #1222

Open
aurbano opened this issue Feb 15, 2024 · 5 comments
Open

Support replacing types with custom ones when transforming the input #1222

aurbano opened this issue Feb 15, 2024 · 5 comments
Labels
enhancement New feature or request

Comments

@aurbano
Copy link

aurbano commented Feb 15, 2024

(Not using the standard issue template as this is a feature request)

I'm migrating from openapi-typescript to orval. In my current setup I've added what could be called "nominal types" - so for instance instead of type userId = number it would use type userId = UserId with the following implementation:

const UserIdSymbol = Symbol('UserId');
type UserId = NominalType<typeof UserIdSymbol>;

Then I have a transformer on the API TS generation that modifies all instances of a userId to use this custom type, and injects an import {UserId} from './types'

Such that we end up with something like:

// Generated types from openapi-typescript
import { UserId } from './custom-types';

// ...

export type UserModel = {
  id: UserId;
  // ...
};

Arguments about the use-cases of this approach and such aside, would this be possible with orval?

I'm trying something like this in the orval config:

input: {
  override: {
    transformer: (api) => {
      // Just testing as an example
      const schema = api.components?.schemas?.ExampleSchema;

      if (schema && 'properties' in schema && schema.properties?.version && 'type' in schema.properties.version) {
          schema.properties.userId.type = UserIdSymbol as any;
      }

      return api;
    },
  },
},

But this just generates the type userId: unknown - so ideally there would be a supported way to do this.

When using openapi-typescript I just transform the type and basically set it to "UserId", so that it then appears as the string content. And I inject the import statement at the top of the file manually (they have a way to inject anything at the top of the file)

@melloware melloware added the question Further information is requested label Feb 15, 2024
@melloware
Copy link
Collaborator

I marked as question. I feel like what you want to do is possible with Orval but I have not done it myself. Hopefully someone who has done this can chime in like @soartec-lab ?

@soartec-lab
Copy link
Collaborator

no, I haven't tried it too.

@Papooch
Copy link

Papooch commented Apr 15, 2024

I have done a similar thing as OP with openapi-generator. Orval seems much more lightweight, but sadly the lack of this feature is a deal breaker for truly type-safe APIs.

@melloware melloware added enhancement New feature or request and removed question Further information is requested labels Apr 16, 2024
@soartec-lab
Copy link
Collaborator

soartec-lab commented Apr 16, 2024

@aurbano @Papooch

I inspected this.
If you change the type in the transformer, only primitive types are supported.
In orval, if the user input type is not a primitive type and not an object, it returns unknown as an unintended type. Becouse, orval cannot determine whether it is really an unknown type or whether the user intended to enter the type.

https://github.com/anymaniax/orval/blob/master/packages/core/src/getters/object.ts#L207

If there is a better way to determine the user-defined one, I will fix this issue.

@Papooch
Copy link

Papooch commented Apr 17, 2024

I think the easiest way to solve this would be to create a new configuration option - something like customTypeMapping, which would take a map of openapi type to typescript type (or possibly the format field - which is how it works in openapi-generator).

Some other inspiration could be found in a similar feature for schema-first GraphQL for NestJS (see customScalarTypeMapping, and also notice the additionalHeader setting)

With that in mind, based on OP's example, I would suggest the following API:

Say the OpenAPI schema looks like this:

type: object
properties:
  id:
    type: string
    format: 'x-user-id' # for example
  name:
    type: string

I would lean towards using the format field as the source for custom types, following the example of openapi-generator

The configuration could then look as follows:

customFormatMapping: {
  'x-user-id': {
    typeName: 'UserId', // use the type name as a string
    importFrom: './custom-types' // optionally add an import (although a custom static header could be enough)
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants