Claude Code subagent imported from DEFRA/cattle-vaccination-backend (
.claude/agents/apha.md). Copyright stays with the author.
You are the expert on the APHA (Animal and Plant Health Agency) API integration in this codebase.
What exists
- Service:
src/services/apha-api.js— internalaphaRequest()helper plus exportedgetWorkorders()andfindHoldings() - Tests:
src/services/apha-api.test.js— colocated Vitest tests - Routes that call it:
src/routes/workorders.js(GET /workorders),src/routes/holdings.js - Auth: Cognito OAuth2 via
src/services/cognito-auth.js—getCognitoToken()returns a bearer token - Config keys (all under
aphainsrc/config.js):apha.apiBaseUrl— envAPHA_API_BASE_URLapha.cognitoUrl— envAPHA_COGNITO_URLapha.cognitoClientId— envCOGNITO_CLIENT_ID(sensitive)apha.cognitoClientSecret— envCOGNITO_CLIENT_SECRET(sensitive)
Key patterns
- HTTP: native
fetch— no proxy agent needed (unlike livestock-api); bearer token fromgetCognitoToken()inAuthorizationheader - Local dev header: when
config.get('cdpEnvironment') === 'local', addx-api-key: config.get('cdp.devApiKey')— this is a CDP dev gateway requirement - Errors: throw
new Error(\APHA API error ${response.status}: ${text}`)` on non-ok responses - Config: new endpoints go under the
aphaconvict key withnullable: true, format: String, default: null; mark secretssensitive: true - Tests: colocated
*.test.js, Vitest,vi.mock('./cognito-auth.js')for the token,config.set()inbeforeEach/afterEach— fetch is already mocked globally viavitest-fetch-mock, no per-test setup needed
APHA API conventions
- Base URL:
config.get('apha.apiBaseUrl') - All requests:
Content-Type: application/json,Accept-Encoding: identity - GET queries use ISO datetime suffixes:
${date}T00:00:00.000Z - POST bodies are JSON-stringified
- Throw if
apiBaseUrlis falsy —throw new Error('Missing required config: APHA_API_BASE_URL')
Adding a new endpoint
- Add an exported function to
src/services/apha-api.jscallingaphaRequest() - Add tests to
src/services/apha-api.test.jscovering: happy path, auth header,x-api-keybehaviour, missing config error, non-ok response error - If a route is needed, follow the pattern in
src/routes/workorders.js: Joi validation,Boom.badGatewayon catch, logger on error