Request and Response Processing

Commercial

This feature is only available in the commercial version of Specmatic. For further details, please check the pricing page.

Specmatic’s processor hooks let you transform traffic that comes to the proxy and the stub. They are useful when the provider and consumer speak a wire format that differs in some way from the actual data that traverses the wire.

For example, a consumer may encrypt data application/json data in the request sent to the provider. And thus while the data in the request body is JSON (application/json), on the wire after encryption it might be a string (text/plain). You may want the specification to capture the application/json format, rather than text/plain. But if you do, the specification no longer describes the actual traffic on the wire. How then might we record a specification that reflects the format of data processed by the application, while still allowing the consumer and provider to exchange data in the expected wire format?

Hooks

Hooks can bridge that gap between the wire format of the HTTP message and the format of the data as processed by the application. They can act as a translation layer between the wire format and the application format.

Specmatic exposes three hook entry points that run at different stages of request or response handling. They give you precise control over how traffic is translated between the consumer, Specmatic, and the provider.

They may be registered in specmatic.yaml as shown below:

hooks:
  pre_specmatic_request_processor: ./hooks/decode_request_from_consumer.sh
  post_specmatic_response_processor: ./hooks/encode_response_to_consumer.sh
  pre_specmatic_response_processor: ./hooks/decode_response_from_provider.sh

In each case, the value of the hook entry is the path to an executable file (script or binary) that Specmatic will invoke at the appropriate time.

pre_specmatic_request_processor

  • Runs in both proxy and stub modes.
  • Receives the incoming request before Specmatic validates it (stub) or forwards it to the provider (proxy).

Use this hook when the consumer sends payloads in a shape that Specmatic should process as-is.

The hook should read the request in the Specmatic example format from the stdin, modify it as needed, and write the transformed request back to stdout.

Sample input to the hook (STDIN):

{
  "http-request": {
    "method": "POST",
    "path": "/api/data",
    "headers": {
      "Content-Type": "application/json"
    },
    "body": {
      "data": "eyJrZXkiOiAidmFsdWUifQ=="  // base64 encoded JSON
    }
  }
}

Sample output from the hook (STDOUT):

{
  "http-request": {
    "method": "POST",
    "path": "/api/data",
    "headers": {
      "Content-Type": "application/json"
    },
    "body": {
      "data": {
        "key": "value"
      }
    }
  }
}

pre_specmatic_response_processor

  • Runs in proxy mode as responses come back from the real provider.
  • Gives you the combined request/response document so you can adjust what Specmatic records.

Sample input to the hook (STDIN):

{
  "http-request": {
    "method": "GET",
    "path": "/api/data"
  },
  "http-response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": {
      "data": "eyJzZWNyZXQiOiAiVmFsdWUifQ=="  // base64 encoded JSON
    }
  }
}

Sample output from the hook (STDOUT):

{
  "http-request": {
    "method": "GET",
    "path": "/api/data"
  },
  "http-response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": {
      "data": {
        "secret": "Value"
      }
    }
  }
}

post_specmatic_response_processor

  • Runs only in stub mode, after Specmatic has generated a response for the consumer.
  • Lets you re-encode payloads, set protocol-specific headers, or add late-stage metadata before the stub returns control to the caller.

Use this hook when the consumer expects something different on the wire (for example base64 or plain text) from what’s in the specification.

Sample input to the hook (STDIN):

{
  "http-response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": {
      "data": {
        "secret": "Value"
      }
    }
  }
}

Sample output from the hook (STDOUT):

{
  "http-response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": {
      "data": "eyJzZWNyZXQiOiAiVmFsdWUifQ=="  // base64 encoded JSON
    }
  }
}

Configuring Processor Hooks

Processor Hooks are configured in specmatic.yaml. Each hook entry should point to an executable file (script or binary) that will be run by Specmatic.

hooks:
  pre_specmatic_request_processor: ./hooks/decode_request_from_consumer.sh
  post_specmatic_response_processor: ./hooks/encode_response_to_consumer.sh
  pre_specmatic_response_processor: ./hooks/decode_response_from_provider.sh

The configuration is evaluated relative to the directory in which Specmatic is launched. You can point at shell scripts, compiled binaries, or even Node/Python entry points… anything executable on your platform.

Notes On Writing Hook Scripts

  • The script must print the transformed JSON document to STDOUT.
  • The script may need to change the Content-Type of the request or response if the transformation alters the payload format.
  • Exit with status 0 to let Specmatic continue. Any non-zero status will be detected by Specmatic. The script’s output will be printed to the console, and the hook unprocessed request will be used instead.
  • Make sure dependencies, language runtimes, etc required by the hook are available in the environment where Specmatic runs.
  • If the hooks are executable scripts, remember to grant execute permissions (chmod +x hooks/*.sh) so Specmatic can invoke the hook scripts.

Sample Project

See hooks-demo for a complete, runnable example.