# GraphQL Service Patterns (@theorchard)

## Schema-First Approach

All services use modular `.graphql` files in `src/schema/`. The schema is the source of truth — TypeScript types are generated from it.

- Entry points: `Query.graphql` and `schema.graphql`
- Codegen glob: `src/schema/[^_]*.graphql` (underscore-prefixed files are skipped)
- Federation directives in `_federation.graphql`

## Resolver Conventions

```typescript
// Query resolvers
export const queryResolvers = { ... } satisfies Partial<QueryResolvers>;

// Type resolvers
export const myTypeResolvers = { ... } satisfies MyTypeResolvers;
```

Import resolver types from `src/generated/`.

## Mapper Keys

Every GraphQL type has a `*Key` interface in `src/resolvers/types/`:

```typescript
// src/resolvers/types/myType.ts
export interface MyTypeKey {
    id: string;
    // Fields available from parent resolver
}
```

Register in codegen config under `mappers:`:
```yaml
mappers:
  MyType: src/resolvers/types/myType#MyTypeKey
```

## DataLoader Factory

Standard pattern across all services:

```typescript
export const dataSchema = z.object({ ... });
export type MyDataLoader = ZodDataLoader<typeof dataSchema>;
export const cacheKeyFn = (key: string) => `TypeName:${key}`;
export const createMyDataLoader = (post: PostFn): MyDataLoader =>
    new ZodDataLoader(dataSchema, { cacheKeyFn, batchFn: ... });
```

## Zod Validation

All external responses validated with Zod. Transform for case mapping:

```typescript
const schema = z.object({
    snake_case_field: z.string(),
}).transform(d => ({
    snakeCaseField: d.snake_case_field,
}));
```

## Cache Control

Hints defined in `src/schema/caching.graphql`. Default: 5 minutes.
- Set `ttl: 0` for user-dependent or flag-dependent data
- Use TTL constants from `src/constants/cache.ts`

## Code Generation

After modifying `.graphql` files:
```bash
yarn generate:types
```

This regenerates `src/generated/index.ts`. Never edit generated files.

## Testing

- Factory builders: `factoryBuilder<T>(defaults, requiredKeys)` → `(overrides?) => T`
- Mocked data sources: `MockedDataSources` provides `jest.Mocked` versions
- Test Zod schemas (valid + invalid), cacheKeyFn, DataLoader instantiation
