@lifeready/core
v9.0.8
Published
Note that the following only applies to the new API.
Keywords
Readme
Key Crypt API
Note that the following only applies to the new API.
General design principles
- Use typing as much as possible
- Use auto inferred type where possible. This makes refactoring easier. Also less likely to cause errors because auto type inference usually resolves to the most strict type.
- Provide utilities to remove boiler plates where possible. Should consider even small and simple boiler plates to improve the ability to refactor, reduce bugs, and maintain consistency.
- Consistent naming convention
- Prefer composition over inheritance. Generally allow for more flexibility in combining primitive functions. Coding style is more functional which makes it easier to reason and debug.
KC specific design
- Provide data in a form that's close to the graphql input and results such that the user of the lib can experiment in the online graphql explorer to test out queries and mutations and expect the results to be the same.
- Original data from API is always retained
- Processed data (eg. decrypted, JSON parsed) are names with consistent suffix, eg.
- cipherMeta (encrypted string) -> cipherMetaClear (decrypted string) -> cipherMetaClearJson (decrypted string JSON parsed)
- plainMeta (plain string) -> plainMetaJson (plain string JSON parsed)
- Allow optional efficiency improvements. eg, the encryption keys can be optionally provide for mutations. If not provided, the mutation will make additional queries to fetch the keys.
- Allow future refactoring to make KC client independent of Angular.
- Transparent encryption and decryption of data where possible
- Most queries should be defined out side of KC-client because the business logic dictate which fields to select.
- Except for certain instances where decrypting the data requires keys not managed within the key graph, eg. the key exchange function use a raw key string from OOB, so it contains functions to fetch and decrypt the data.
gqlTypedonly has generic type on the return of the query or mutation, not on the input variable. Usually the LrMutation are created in a function, which has explit input types. The function will also do other preparation for the mutation, so the input type is not just the input variables. Because the end user does not need to interact with the gql mutation, it doesn't need an input variable type.- Use string enum instead of string constant union types because sometime you need to drop to JS and string typos becomes easy.
- Return LrMutation where possible so that the user can choose how to compose the mutations. Unfortunately that's not always possible if subsequent steps depend on previous mutations. But these instances are rare.
Good to know
JSON.stringify(void 0)returnsundefinedso no need for this:input JSON.stringify(input)- When using mergeMap,concatMap, switchMap you can just return a promise.
Future
- Being able to cancel apollo requests would be nice. Let's wait for support from apollo on that.
Convention
- Suffixes
Optionis user to group variables together.Inputis graphql mutation variableMutationis a graphql mutationQueryis a graphql query
- When a graphql mutation wants to clear a field, pass in undefined or null as the variable value. If you want to prove that the user cleared the field, you can use empty string, which will get encrypted. And all encryption has a timestamp it can be verified to be cleared by the user at a certain time.
- The return type of mutations should not use xxxNode types because the mutation performs a specific selection of fields in the result. The return type should be customised to include only those fields.
- Use
gqlTypedinstead ofgqland co-locate the interface for the result just above the query definition. Example
export interface CancelKeyExchangeMutation {
cancelKeyExchange: {
keyExchange: {
id: ID;
};
};
}
export const CancelKeyExchangeMutation = gqlTyped<CancelKeyExchangeMutation>`
mutation CancelKeyExchangeMutation($input: CancelKeyExchangeInput!) {
cancelKeyExchange(input: $input) {
keyExchange {
id
}
}
}
`;Notice the name of the interface and the query is the same. The name CancelKeyExchangeMutation should always be repeated 4 times: as the interface name, the query variable name, the gqlTyped generic type, and the mutation name.
