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

Generate TS interfaces from OAS #3

Merged
merged 4 commits into from
Nov 9, 2021

Conversation

salemhilal
Copy link
Contributor

Rather than redeclaring all of our types, let's generate them from our OAS JSON file and save some repetition.

Some specifics:

  1. yarn generate now generates src/apiTypes.ts in a way that agrees with out prettierrc.
  2. apiTypes.ts and yarn.lock are marked as generated, so they should be collapsed in PRs
  3. I used the generated PricePlan and MeteredComponent types in the PlanPicker component and story.
  4. I added some metered component mock data in preparation for that work.

Rather than redeclaring all of our types, let's generate them from our
OAS JSON file and save some repetition.
I also added notes for a few things we should have stories for.
@salemhilal salemhilal self-assigned this Nov 8, 2021
React needs to be v16.8 or higher for hooks, and React v17 should work just fine
Copy link
Contributor

@zeppelinnn zeppelinnn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lg!

@@ -46,6 +46,8 @@ yarn test
yarn storybook
# Build storybook once
yarn build-storybook
# Fetch our openapi spec and generate fresh TypeScript types
yarn generate
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: i changed this in octane-portal to be yarn codegen as i felt it was more self-descriptive. Mentioning it for consistency.

},
"peerDependencies": {
"react": "^16.0.0"
"react": ">=16.8.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yay <3

Comment on lines +1643 to +1657
responses: {
/** Default error response */
DEFAULT_ERROR: {
content: {
'application/json': components['schemas']['Error'];
};
};
/** Unprocessable Entity */
UNPROCESSABLE_ENTITY: {
content: {
'application/json': components['schemas']['Error'];
};
};
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great that we have more visibility into the generated error types. This was something i felt was missing previously.

description?: string | null;
/** Whether measurement values are to be considered incremental (versus a running total) */
is_incremental?: boolean;
meter_type?: unknown;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

came here to look at what the types were for DB enums. looks like unknown. Any thoughts on how to approach this? For some well-defined types like meter_type, I feel it's reasonable to manually represent that, knowing it's unlikely to change in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for some of these, we may need to write a script that uses the openapi-typescript API. they have a few examples for how to deal with custom field types:
https://github.com/drwpow/openapi-typescript#custom-formatter

there are some properties, like meter_name on MeteredComponents, that are unknown because the type property is missing from the actual openapi.json file. I don't totally know what to do about that but I talked with Ahmed for a bit yesterday to see if there were options (we didn't find anything obvious).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we were doing similar for the graph QL codegen step as well. It's good to get rid of the unknown but also exposes us to some potential bugs if we aren't careful

src/apiTypes.ts Show resolved Hide resolved
Comment on lines +13 to +18
* Test cases to implement:
* 1. No base price
* 2. Multiple metered components
* 3. Discounts
* 4. Limits
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: these cases seem most applicable to the individual price plan (rather than the plan picker). Seems like two separate things that we'd want to distinctly and individually test/validate.

src/components/PlanPicker.stories.tsx Show resolved Hide resolved
Comment on lines +40 to +49
limit: 400.0,
meter_name: 'storage',
price_scheme: {
display_name: null,
name: null,
prices: [{ price: 300.0 }],
scheme_type: 'PriceSchemeType.FLAT',
time_unit_name: null,
unit_name: 'gigabyte',
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you're using storage which i presume is a gauge, I think you'd want to include an associated time unit name, otherwise it's unclear what unit is being billed on (i.e. if my price is 300 per GB/month then 1 GB at the halfway point of the month should total $150)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a storage meter and billed on it in a few different ways. all this data came straight from the API; it's not hand-written, to be clear.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's odd that you could create a scheme on a gauge without having to specify a time unit name, though maybe that was just a validation step added as part of the portal UI

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh wow the answer is even dumber than that; Storage is a counter.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha that makes a lot of sense, glad nothing is broken :P

const billingSchedule =
period === 'month' ? 'Billed monthly' : `Billed every ${period}`;
const formattedBasePrice = formatCurrency(basePrice);
const hasBasePrice = basePrice != null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add similar utils for checking for null/undefined as in oc portal? I typically liked those for readability, though the naming i believe had some overlap with some other system utils (just recall having some autoimport issues a few times)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I was thinking about that. I learned the hard way (when implementing Limits) that if the lhs resolves to 0 (instead of null or undefined), a literal 0 will get rendered.

{hasBasePrice && (
<div className='base-price'>
<span className='label starting-at'>Starting at </span>
<span className='cost'>{formattedBasePrice}</span>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use a more representative className, i.e. className='base-price-value'

Mainly want to avoid the use of the cost nomenclature and think about it more as a price.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ugh i accidentally pushed that commit into the next PR's branch but it's there.

@salemhilal salemhilal merged commit 5bb97ad into main Nov 9, 2021
@salemhilal salemhilal deleted the salem/generate-ts-types-from-oas branch November 9, 2021 17:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants