How do you generate types dynamically? How do you write a script that creates some typescript code? The approach most people would recommend is to use Abstract Syntax Tree manipulations. I was working on a deadline to implement types for our OpenAPI client, and I would have missed our release window. I needed something different and easier to build. Luckily, a friend recommended me a library I didn't know: code-block-writer. I fall in love with it at first sight.
3. A little bit about me
Matteo Collina, Ph.D.
Co-Founder & CTO, Platformatic
Node.js Technical Steering Committee member
Board member OpenJS Foundation
8 years as a consultant focused on Node.js
Created Fastify and Pino
Subscribe to my newsletter at https://nodeland.dev.
17. How can we produce an amazing developer
experience without tight coupling between client
and server?
18. According to all our surveys, ~80% of
developers prefer REST to GraphQL
19. How can we automatically generate a client for
our REST APIs?
Ideally, the generated code should minimal and simple
20. OpenAPI is a standard way to define REST APIs
Integrated in most frameworks
Automatically generating OpenAPI
documentation pages is simple.
21. Client generation: Requirements
1. Routes defined via OpenAPI
2. No data validation at runtime / let’s not waste any time on the client
3. Fully typed to catch developer mistakes via the editor (or at compile time)
4. Only use fetch() at runtime with no dependencies.
22. First try: Use the TypeScript compiler API
Generating a simple function:
Credits https://dev.to/rametta/typescript-code-generation-epn
23. First try: Use the TypeScript compiler API
It took ~60 lines to generate 3.
This is a 20x expansion.
24. A 20x expansion seem quite big tree to climb…
and we did not want to climb any trees.
25. Second try: use call code-block-writer
~10 lines to generate 3. A ~3x expansion rate is a much better tradeoff.
The code that generates the function is readable by a human.
It’s homomorphic, because it
maintains the relationship
between the various part of
our generated code.
Warning: the generated code is not
guaranteed to be valid!
29. From OpenAPI definitions to types
● Every path (route) defined in the OpenAPI specification has an optional
operationId, which we can use to derive a method name from. If it’s missing, we
can generate one!
● Split the types definition from the actual code that is being executed to increase
debuggability (and support JavaScript, too!).
● Fully resolve shared schemas in the OpenAPI definitions and only generate 1
level types to avoid having the users reusing the defined types too much.