This short walkthrough illustrates how you can easily extend or generate your base Types for your TypeScript application easily using the AWS Ampligy/Apollo GraphQL codegen.
Note, you should be slightly familiar with GraphQL and Apollo or AWS Amplify GraphQL services, and the basics of TypeScript
Why are base types important?
Base types, and specifically using TypeScript with the code generator allows us to make sure that the types we are creating, updating, or listing from our GraphQL api conform to our schema.
This is especially important when designing our API function calls, so that everything we submit is of the correct shape and format, preventing us from dealing with errors later that could take a long time to debug.
I work in Healthcare, specifically making web and mobile applications for physicians and administrators.
So, we're going to use a simple healthcare focused schema to illustrate the example using medications and interactions.
Schema:
# schema.graphql
# @model automatically generates api calls for our API using GraphQL, AppSync & DynamoDB
type Patient @model {
# basic patient information
id: ID!
name: String!
sex: String!
encounters: [Encounter] @connection(name: "Encounters")
}
type Encounter @model {
# when a patient sees a doctor, that's an Encounter
id: ID!
reason: String!
patient: Patient @connection(name: "Encounters")
orders: [Order] @connection(name: "EncounterOrders")
}
type Order @model {
# For lab tests like xrays, MRI, etc
id: ID!
order: String!
# Tie the order to the encounter/patient visit it was created on
Encounter: Encounter @connection(name: "EncounterOrders")
}
This is a basic one-to-many schema, that models a patient, an encounter with a physician, and sample clinical orders that can be made.
To generate your API, use apollo or amplify GraphQL codegen using:
$ amplify codegen
Follow the walkthrough, and be sure to select TypeScript for your code generation language.
You'll have a filed called API.ts generated, most likely in your ./src folder if you're using React, React Native, etc.
Open API.ts where you saved it, and look for the type GetPatientQuery:
export type GetPatientQuery = {
getPatient: {
__typename: "Patient",
id: string,
name: string,
sex: string,
encounters: {
__typename: "ModelEncounterConnection",
items: Array< {
__typename: "Encounter",
id: string,
reason: string,
} | null > | null,
nextToken: string | null,
} | null,
} | null,
};
How do we extract the Patient base type?
By utilizing TypeScripts Utility types to transform these types into the types all of our projects can use.
We need to remove the possible nullish return of the API call, and any unnecessary annotations.
export interface Patient
extends Omit<Exclude<GetPatientQuery["getPatient"], null>, "__typename"> {}
That's it!
What's happening here is the Exclude utility type is removing/excluding the "null" of the type, which exists in case no data is returned/found.
Next, the Omit utility type removes the "__typename" label that is generated by the codegen to tell us the base type name.
That's it!
We can now use Patient as a base type for usage in our React/Vue/Angular etc web apps. We have the types for mapping, adding, and deleting types.
We can extend this to all of the other types that we created in the Schema, too.
And they automatically update if we change our schema!
Cheers, and hope this was helpful!
Need help with Amplify, cloud, or full-stack? I'm available for consulting.
Top comments (2)
I found I had to also exclude "undefined".
I refer to your technique in Using Typescript with AWS Amplify API