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

Readonly modifier is being ignored #193

Open
schimini opened this issue Jan 3, 2022 · 9 comments · May be fixed by #332
Open

Readonly modifier is being ignored #193

schimini opened this issue Jan 3, 2022 · 9 comments · May be fixed by #332
Labels
enhancement New feature or request

Comments

@schimini
Copy link

schimini commented Jan 3, 2022

Hi, not sure if this is a bug, it's looking more like a feature request, but I wanted to know if I could use the readonly property modifier to generate different types for creation requests ( POST, PUT) and read requests (GET) using the same schema.

My use case is:
My schema has an id, and when creating the entity via post I don't want to provide an id. But also I don't want to duplicate every schema, or use extension just for this.

Could someone look into this? Should I dive into a possible PR?

@luisfpg
Copy link
Contributor

luisfpg commented Jan 3, 2022

Sorry, but we focus on implementing standard specification.
The way to go would be to define different schemes.

@luisfpg luisfpg closed this as completed Jan 3, 2022
@luisfpg luisfpg added the question Further information is requested label Jan 3, 2022
@schimini
Copy link
Author

schimini commented Jan 3, 2022

@luisfpg thanks for responding.

Isn't readOnly standard since it is described in the openAPI sepcification doc?

@luisfpg luisfpg reopened this Jan 4, 2022
@luisfpg
Copy link
Contributor

luisfpg commented Jan 4, 2022

Sorry, I've misunderstood your question.
I think the readonly modifier should be generated for properties marked as readOnly: true in the schema.
AFAIK, there's no TypeScript modifier for writeonly so far.

@luisfpg luisfpg added enhancement New feature or request and removed question Further information is requested labels Jan 4, 2022
@schimini
Copy link
Author

schimini commented Jan 4, 2022

No problem!

I checked and I don't think typescript's readonly will be usefull in this case (at least by itself). openAPI's readOnly is meant to say that objects can't be constructed with a specific property, whilst typescript's readonly is meant to block the property from being updated (implying that it should be initialized).

Basically if something like this was generated:

export interface TestSchema {
  readonly id: number;
  prop: string;
}

typescript complier would throw an error when trying to do this:

//apiTestPost(id: number, body: TestSchema): : Observable<TestSchema>

this.service.apiTestPost(id, {prop: 'test string'})

because id is not present in the body.

TLDR; I think openAPI's readOnly translates into two possibilities:

The first one is to generate an analogous interface without readonly properties.

The other is basically the same thing but using ts type checker by declaring:

type KeysOfType<T, SelectedType> = {
  [key in keyof T]: SelectedType extends T[key] ? key : never;
}[keyof T];

type Optional<T> = Partial<Pick<T, KeysOfType<T, undefined>>>;

type IfEquals<X, Y, A=X, B=never> =
  (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? A : B;

type WritableKeys<T> = {
  [P in keyof T]: IfEquals<{ [Q in P]: T[P] }, { -readonly [Q in P]: T[P] }, P>
}[keyof T];

type WritableObject<T> = {
  [K in WritableKeys<T>]: T[K]
};

type WriteableNoOptional<T> = Omit<WritableObject<T>, KeysOfType<T, undefined>>

// and then generating something like this:
export interface TestSchema {
  readonly id: number;
  prop: string;
}

export type WriteableTestSchema = WriteableNoOptional<TestSchema> & Optional<TestSchema>;

//apiTestPost(id: number, body: WriteableTestSchema ): : Observable<TestSchema>

@schimini
Copy link
Author

Any thoughts on this @luisfpg ?

@luisfpg
Copy link
Contributor

luisfpg commented Jan 20, 2022

Generating 2 interfaces from a single input is out of question, because the way the generator is done.
There's another request which always gets blocked by the same fact: generating a proper Enum type for inline enums.
So, in this sense, I'd say this would always be a limitation of the library: not supporting readOnly nor writeOnly.

@schimini
Copy link
Author

I don't understand the limitations of the generator and I won't debate you on that for sure. Since 2 interfaces are out of question the method I wrote above might work. You only generate one interface (with the readonly modifier on the readOnly properties) and then depending on the http method for an endpoint the body param could use the helpers defined in my other comment in conjunction with:

type WriteableSchema<T> =  WriteableNoOptional<T> & Optional<T>

//method
apiTestPost(id: number, body: WriteableSchema<TestSchema>) : Observable<TestSchema>

I know it looks cumbersome for a low reward, and it might slow the ts compiler / linter a bit , and for that reason a flag could be added ( --experimental or something), but I think it works without compromising any part of the generator.

@luisfpg
Copy link
Contributor

luisfpg commented Jan 21, 2022

I'm sorry, but I really have no time to work on the generator nowadays...
If you could provide a PR, that would be greatly appreciated.
What I do think is that for models that don't have any readOnly properties, nothing should change at all in the generation...

@schimini
Copy link
Author

No problem. I'll try to make a PR for it.

What I do think is that for models that don't have any readOnly properties, nothing should change at all in the generation...

About this I'll take it into consideration. I'll probably use some flag, since I've seen that pattern before in the generator code.

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

Successfully merging a pull request may close this issue.

2 participants