-
-
Notifications
You must be signed in to change notification settings - Fork 754
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
fix: API improvements aligning the types to our schemas #4650
Changes from 4 commits
d90dd00
64c9b2b
b5e14d2
b60e581
e87a037
dd8e9b8
e2ea521
cd1a26f
fe25a90
7577c09
2891ff9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -238,7 +238,7 @@ class StrategyController extends Controller { | |
} | ||
|
||
async createStrategy( | ||
req: IAuthRequest<unknown, CreateStrategySchema>, | ||
req: IAuthRequest<unknown, unknown, CreateStrategySchema>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Body should be the third parameter |
||
res: Response<StrategySchema>, | ||
): Promise<void> { | ||
const userName = extractUsername(req); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -402,6 +402,14 @@ export interface IImportData extends ImportCommon { | |
data: any; | ||
} | ||
|
||
// Create project aligns with #/components/schemas/createProjectSchema | ||
// joi is providing default values when the optional inputs are not provided | ||
// const data = await projectSchema.validateAsync(newProject); | ||
export type CreateProject = Pick<IProject, 'id' | 'name'> & { | ||
mode?: ProjectMode; | ||
defaultStickiness?: string; | ||
}; | ||
Comment on lines
+407
to
+411
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aligning with the schema where only required fields are id and name: https://github.com/ivarconr/unleash-enterprise/blob/4544d0abfefbdcab5be633e4d0252c7e7564ce09/src/openapi/spec/create-project-schema.ts#L6 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice. Could we use OpenAPI to set defaults instead? It has a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The challenge here is that the spec is in the enterprise repository. Based on our latest conversations, this logic should be moved to enterprise. So in theory, I think that's possible but I don't know how much effort it will be to move all project creation logic to enterprise, and then do proper unit testing to validate that joi and OpenAPI validate and use defaults in the same way. So, I rather leave that for another day |
||
|
||
export interface IProject { | ||
id: string; | ||
name: string; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Important one so we have to declare all properties in the schema. This is input, so I'm not sure how specific we want to be with input data. Maybe we don't need this
@thomasheartman maybe you remember some decisions around additional properties. My take is that for input is not so important, as customers might want to extend Unleash, but I'm not 100% sure... I see in some cases we're doing it so should be fine:
unleash/src/lib/openapi/spec/create-user-schema.ts
Lines 3 to 6 in b60e581
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the discussion we had previously was:
always allow additional properties on inputs, never on outputs.
Following the old adage to be liberal in what you accept, but strict in what you return, we thought it best to allow any additional properties coming in. We didn't want to break a user's experience because they added a field that we don't recognize.
On the output front, we want to be very clear about what we expect and we want the types to be accurate. For that to be true, we needed conversions to fail if they contained extra data.
Based on that, I don't think we should have additionalProperties: false here. Did you do it for a reason?
On the other hand, one drawback of never using additionalProperties: false on input data, is that it makes creating union types harder (or almost impossible without a discriminator).
But that said, if we require a property to be supplied by the user, then we can use the
required
property.Could you elaborate a bit on this? I'm not sure I understand.
Anyway, my suggestion is to remove this line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did this to unveil the properties that were not declared in the spec. Turns out, this is not needed, but I discovered a way out of OpenAPI that allows us to define new properties without having to declare them in the spec.
Of course, this is not what we want, and I believe this was done by mistake or by not knowing that the type was backed by an OpenAPI spec. The trick is that this pattern also removes all safeguards from type safety.
The pattern (that we have to avoid) goes as follows:
Now, because we allow additional properties on the first type, anything optional can be added to the second type without having to define the property in the OpenAPI spec (this doesn't apply to mandatory fields because all additional properties are inherently optional).
This leads to accidentally adding new optional parameters to internal types that do not get proper documentation in our spec.
What's the solution?
One possible solution is to avoid defining custom types and instead always refer to the schema type. Instead of:
We can use the schema and pick the fields we want from the schema:
This then sheds light on the missing fields at compile time:
