user = getUser(); sendEmail( `Thank you ${user.first} ${user.last} for placing your order with us!` ); } Our refactor broke this! And there is now compiler in JS to warn us.
await fetch(API_URL + "/userinfo"); const userInfo: User = await response.json(); } type User = { id: number; email: string; }; ❗❗We are casting ‘any’ to ‘User’ This has no type safety guarantee
await fetch(API_URL + "/userinfo"); const userInfo: User = await response.json(); } type User = { id: number; email: string; }; ❗❗We are casting ‘any’ to ‘User’ This has no type safety guarantee If the API changes this will not fail or warn us in any way. ⚠
await fetch(API_URL + "/userinfo"); const userInfo: User = await response.json(); } type User = { id: number; email: string; }; ❗❗We are casting ‘any’ to ‘User’ This has no type safety guarantee If the API changes this will not fail or warn us in any way. ⚠ We must update/maintain our types every time API changes ⚠
await fetch(API_URL + "/userinfo"); const userInfo: User = UserSchema.parse(await response.json()); } const UserSchema = z.object({ id: z.number(), email: z.string(), }); type User = z.infer<typeof UserSchema>; This parsing will fail if API changes. It ensure we are receiving the correct type. Better. ✅
await fetch(API_URL + "/userinfo"); const userInfo: User = UserSchema.parse(await response.json()); } const UserSchema = z.object({ id: z.number(), email: z.string(), }); type User = z.infer<typeof UserSchema>; This parsing will fail if API changes. It ensure we are receiving the correct type. Better. ✅ We still need to manually update/maintain our schema ⚠
cation • Speci fi cation de fi ning the API request/response formats • JSON or YAML • Serves as an API Documentation • Tools and code generators for client SDKs
our Open API speci fi cation • We can also generate client SDK or types • Language agnostic ( YAML -> Java, Typescript, Kotlin, Swift, GO, etc ) • Multiple open source tools to facilitate this • We get typed models and endpoints • Automatic code generation • Saves a lot of development time
BE APIs • Generated Swagger API documentation • Generated client SDK / types • Client and BE use the same types / de fi nitions • Many things can be automated and generated • Systems using up to date types, making everything more robust and safe
by a strongly typed schema • Schema de fi nes data types • Schema lists available operations / queries • Serves as a contract between client and server • Promotes easier collaboration and keeping data types in sync
String lastName: String email: String! friends: [User] } type Query { getUserInfo: User getFriendsSuggestions: [User] } type Mutation { addFriend(userId: Float!): User } query GetUserInfo { } Name the query
String lastName: String email: String! friends: [User] } type Query { getUserInfo: User getFriendsSuggestions: [User] } type Mutation { addFriend(userId: Float!): User } query GetUserInfo { getUserInfo } Name the query Choose the operation
query GetUserInfo { getUserInfo { id email firstName lastName } } `; type UserInfoResponse = { id: string; email: string; firstName: string; lastName: string; }; We are again manually de fi ning our types 🫠
query GetUserInfo { getUserInfo { id email firstName lastName } } `; type UserInfoResponse = { id: string; email: string; firstName: string; lastName: string; }; We are again manually de fi ning our types 🫠 We must keep properties names and types in sync with GQL schema
work ? • Is external APIs schema hard to determine ? • Is it a problem to maintain types ? • Is it hard to identify changes in external types ? • Maybe this can be automated via code generation