|
| 1 | +# Account GraphQL Operations Refactoring |
| 2 | + |
| 3 | +This document explains the refactoring of account-related GraphQL operations to use Apollo Angular's typed GQL service pattern. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +All account operations have been migrated from using raw GraphQL queries/mutations with Apollo client to using generated, type-safe Apollo Angular GQL services. |
| 8 | + |
| 9 | +## What Changed |
| 10 | + |
| 11 | +### Before |
| 12 | +```typescript |
| 13 | +// Direct Apollo usage |
| 14 | +this.apollo.query({ |
| 15 | + query: GET_ACCOUNT_BY_EMAIL, |
| 16 | + variables: { email } |
| 17 | +}) |
| 18 | + |
| 19 | +this.apollo.mutate({ |
| 20 | + mutation: CREATE_ACCOUNT, |
| 21 | + variables: { email, password } |
| 22 | +}) |
| 23 | +``` |
| 24 | + |
| 25 | +### After |
| 26 | +```typescript |
| 27 | +// Generated typed GQL services |
| 28 | +this.getAccountByEmailGQL.fetch({ variables: { email } }) |
| 29 | +this.createAccountGQL.mutate({ variables: { email, password } }) |
| 30 | +this.loginAccountGQL.mutate({ variables: { email, password } }) |
| 31 | +``` |
| 32 | + |
| 33 | +## Generated GQL Classes |
| 34 | + |
| 35 | +The following injectable GQL classes are now available in `src/generated/graphql.ts`: |
| 36 | + |
| 37 | +### Queries |
| 38 | +- **GetAccountByEmailGQL** - Fetch account by email |
| 39 | +- **GetAccountsGQL** - Fetch all accounts |
| 40 | + |
| 41 | +### Mutations |
| 42 | +- **CreateAccountGQL** - Create a new account |
| 43 | +- **LoginAccountGQL** - Login with email and password (changed from Query to Mutation for proper authentication semantics) |
| 44 | + |
| 45 | +## Usage |
| 46 | + |
| 47 | +### Using AccountService (Recommended) |
| 48 | +The AccountService provides high-level methods that wrap the GQL classes with error handling and state management: |
| 49 | + |
| 50 | +```typescript |
| 51 | +import { AccountService } from './models/account/account-service'; |
| 52 | + |
| 53 | +export class MyComponent { |
| 54 | + private readonly accountService = inject(AccountService); |
| 55 | + |
| 56 | + async login() { |
| 57 | + const account = await this.accountService.loginAccount(email, password); |
| 58 | + } |
| 59 | + |
| 60 | + async register() { |
| 61 | + const result = await this.accountService.createAccount(email, password); |
| 62 | + } |
| 63 | +} |
| 64 | +``` |
| 65 | + |
| 66 | +### Using GQL Classes Directly (Advanced) |
| 67 | +For more control, you can inject the GQL classes directly: |
| 68 | + |
| 69 | +```typescript |
| 70 | +import { LoginAccountGQL, CreateAccountGQL } from './generated/graphql'; |
| 71 | +import { firstValueFrom } from 'rxjs'; |
| 72 | + |
| 73 | +export class MyComponent { |
| 74 | + private readonly loginGQL = inject(LoginAccountGQL); |
| 75 | + private readonly createAccountGQL = inject(CreateAccountGQL); |
| 76 | + |
| 77 | + async login(email: string, password: string) { |
| 78 | + const result = await firstValueFrom( |
| 79 | + this.loginGQL.watch({ variables: { email, password } }).valueChanges |
| 80 | + ); |
| 81 | + return result.data?.loginAccount; |
| 82 | + } |
| 83 | + |
| 84 | + async register(email: string, password: string) { |
| 85 | + const result = await firstValueFrom( |
| 86 | + this.createAccountGQL.mutate({ variables: { email, password } }) |
| 87 | + ); |
| 88 | + return result.data?.createAccount; |
| 89 | + } |
| 90 | +} |
| 91 | +``` |
| 92 | + |
| 93 | +## Adding New Operations |
| 94 | + |
| 95 | +To add a new account operation: |
| 96 | + |
| 97 | +1. Create a `.graphql` file in `src/graphql/`: |
| 98 | +```graphql |
| 99 | +# src/graphql/update-account.mutation.graphql |
| 100 | +mutation UpdateAccount($id: Int!, $email: String!) { |
| 101 | + updateAccount(id: $id, email: $email) { |
| 102 | + id |
| 103 | + email |
| 104 | + createdAt |
| 105 | + updatedAt |
| 106 | + } |
| 107 | +} |
| 108 | +``` |
| 109 | + |
| 110 | +2. Run code generation: |
| 111 | +```bash |
| 112 | +npm run codegen |
| 113 | +``` |
| 114 | + |
| 115 | +3. The new `UpdateAccountGQL` class will be generated and can be injected: |
| 116 | +```typescript |
| 117 | +import { UpdateAccountGQL } from './generated/graphql'; |
| 118 | + |
| 119 | +export class AccountService { |
| 120 | + private readonly updateAccountGQL = inject(UpdateAccountGQL); |
| 121 | + |
| 122 | + async updateAccount(id: number, email: string) { |
| 123 | + const result = await firstValueFrom( |
| 124 | + this.updateAccountGQL.mutate({ variables: { id, email } }) |
| 125 | + ); |
| 126 | + return result.data?.updateAccount; |
| 127 | + } |
| 128 | +} |
| 129 | +``` |
| 130 | + |
| 131 | +## Benefits |
| 132 | + |
| 133 | +1. **Type Safety**: Full TypeScript type checking for all GraphQL operations |
| 134 | +2. **Auto-completion**: IDE provides suggestions for available fields and variables |
| 135 | +3. **Consistency**: All operations follow the same pattern |
| 136 | +4. **Maintainability**: Easier to add, modify, and remove operations |
| 137 | +5. **Code Generation**: No manual type definitions needed |
| 138 | + |
| 139 | +## Migration Notes |
| 140 | + |
| 141 | +- Old `account.queries.ts` and `account.mutations.ts` files have been removed |
| 142 | +- The `Account` interface was updated to match generated types (`updatedAt?: string | null`) |
| 143 | +- All existing components using AccountService continue to work without changes |
0 commit comments