Files
apophis-fastify/docs/getting-started.md
T

4.2 KiB

Getting Started with APOPHIS

Get from install to your first behavioral bug in 10 minutes.

Prerequisites

  • Node.js 20.x or 22.x
  • A Fastify app with @fastify/swagger registered

Step 1: Install

npm install apophis-fastify fastify @fastify/swagger

Step 2: Scaffold

apophis init --preset safe-ci

This creates:

  • apophis.config.js — config with a quick profile
  • APOPHIS.md — preset-specific guidance
  • Package script: npm run apophis:verify

Step 3: Add One Behavioral Contract

Pick one important route. Add an x-ensures clause that checks behavior across operations:

app.post('/users', {
  schema: {
    'x-category': 'constructor',
    'x-ensures': [
      // BEHAVIORAL: Creating a user must make it retrievable
      'response_code(GET /users/{response_body(this).id}) == 200'
    ]
  }
}, async (request, reply) => {
  const { name } = request.body;
  const id = `usr-${Date.now()}`;
  reply.status(201);
  return { id, name };
});

Step 4: Run Verify

apophis verify --profile quick --routes "POST /users"

APOPHIS will:

  1. Discover routes from your Fastify app
  2. Filter to POST /users
  3. Generate test data from the schema
  4. Execute the route
  5. Check the behavioral contract
  6. Print pass/fail, seed, and replay command

Example Failure

If your GET /users/:id handler has a bug (always returns 404), APOPHIS catches it:

Contract violation
POST /users
Profile: quick
Seed: 42

Expected
  response_code(GET /users/{response_body(this).id}) == 200

Observed
  GET /users/usr-123 returned 404

Why this matters
  The resource created by POST /users is not retrievable.

Replay
  apophis replay --artifact reports/apophis/failure-2026-04-28T12-30-22Z.json

Next
  Check the create/read consistency for POST /users and GET /users/{id}.

Step 5: Replay and Fix

Copy the replay command and run it:

apophis replay --artifact reports/apophis/failure-2026-04-28T12-30-22Z.json

Fix the bug in your handler. Re-run verify. The failure should now pass.

Next Steps

  • Add more routes to your profile: apophis verify --profile quick --routes "POST /users,PUT /users/:id"
  • Run all routes: apophis verify --profile quick
  • Run only changed routes in CI: apophis verify --profile ci --changed
  • Add observe mode for runtime drift detection: see docs/observe.md
  • Add qualify mode for scenario, stateful, and chaos checks: see docs/qualify.md

Config Reference

// apophis.config.js
export default {
  mode: 'verify',
  profile: 'quick',
  profiles: {
    quick: {
      name: 'quick',
      mode: 'verify',
      preset: 'safe-ci',
      routes: ['POST /users']
    },
    ci: {
      name: 'ci',
      mode: 'verify',
      preset: 'safe-ci',
      routes: []
    }
  },
  presets: {
    'safe-ci': {
      name: 'safe-ci',
      depth: 'quick',
      timeout: 5000,
      parallel: false,
      chaos: false,
      observe: false
    }
  },
  environments: {
    local: {
      name: 'local',
      allowVerify: true,
      allowObserve: true,
      allowQualify: false,
      allowChaos: false,
      allowBlocking: true,
      requireSink: false
    }
  }
};

Monorepo Workspaces

APOPHIS supports workspace-wide operations with the --workspace flag.

Root package.json scripts

{
  "scripts": {
    "apophis:verify": "apophis verify --workspace --profile quick",
    "apophis:doctor": "apophis doctor --workspace",
    "apophis:qualify": "apophis qualify --workspace --profile ci"
  }
}

Workspace fan-out

Run verify across all packages:

apophis verify --workspace --profile quick --format json

Output is package-attributed:

{
  "exitCode": 0,
  "runs": [
    {
      "package": "api",
      "cwd": "/repo/packages/api",
      "artifact": { ... }
    },
    {
      "package": "web",
      "cwd": "/repo/packages/web",
      "artifact": { ... }
    }
  ]
}

Supported commands

  • apophis verify --workspace
  • apophis doctor --workspace

Exit Codes

Code Meaning
0 Success
1 Behavioral / qualification failure
2 Usage, config, or environment safety violation
3 Internal APOPHIS error
130 Interrupted (SIGINT)