Wednesday, 26 August 2026

Traffic Parrot 5.62.1 released, what's new?

We have just released version 5.62.1. Here is a list of the changes that came with the release:

Features

  • The messaging Add/Edit mapping editors (JMS, native IBM® MQ and file message) now offer the NOT (negate a matcher) request body matcher, as the HTTP and gRPC editors already do. Choosing it in the Request body dropdown replaces the request body field with a NOT child matcher sub-editor where you pick the matcher to negate and type its value, so you can stub "everything except this" without hand-editing the mapping JSON. The child matcher dropdown offers the leaf matchers that can be negated (equalTo, contains, doesNotContain, matches, doesNotMatch, equalToJson, matchesJson, matchesJsonPath, equalToXml, matchesXml and matchesXPath); the SWIFT and FIX field matchers and the JMS-only binaryEqualTo matcher are not offered as children and are still negated by writing the matcher in the mapping JSON. The mapping is saved as a nested "bodyMatcher": {"not": {"contains": "CANCELLED"}}, reopening it restores the body matcher, child matcher and child value into the sub-editor, and the messaging mappings list now shows a composite matcher as a readable one-line summary such as not (contains 'CANCELLED') instead of the raw matcher JSON (matching how the HTTP and gRPC mapping lists and the messaging import preview already render it). The and and or operators are offered in the same dropdown; see Authoring and and or in the messaging editor.
  • The messaging Add/Edit mapping editors (JMS, native IBM® MQ and file message) now also offer the AND (all sub-matchers match) and OR (any sub-matcher matches) request body matchers, so all three logical operators are now offered in the request body matcher dropdown of every mapping editor that has one (see Logical operators). Choosing AND or OR in the Request body dropdown replaces the request body field with a Sub-matchers panel holding two rows, each one a matcher plus the value to match it against. Add sub-matcher appends a row and the bin button on a row removes it, down to the two sub-matchers that and and or need to mean anything. A row's matcher dropdown offers the same leaf matchers as the NOT child matcher dropdown (equalTo, contains, doesNotContain, matches, doesNotMatch, equalToJson, matchesJson, matchesJsonPath, equalToXml, matchesXml and matchesXPath), and a sub-matcher value is a multi-line field, so a multi-line JSON or XML body can be typed or pasted straight into a sub-matcher row and keeps its line breaks when the mapping is saved and reopened. The mapping is saved as "bodyMatcher": {"and": [{"contains": "ORDER-"}, {"doesNotContain": "DRAFT"}]}, reopening it restores one row per sub-matcher in the order it was saved, and the messaging mappings list shows the matcher as a readable one-line summary such as and (contains 'ORDER-', doesNotContain 'DRAFT') instead of the raw matcher JSON.
  • A JMS response body can now be served from a file in the __files directory, the messaging counterpart of an HTTP file-backed response. Set bodyFileName on a JMS mapping's response (a path under __files, resolved against the __files directory beside the mapping's jms-mappings directory, per-scenario for scenario-scoped mappings) in place of an inline text value; the two are mutually exclusive. Setting both, or referencing a file that does not exist, is rejected at load time and the messaging mappings fail to load until it is corrected (the error names the mapping and the missing file). The file's contents are UTF-8 text and are run through the same Handlebars templating as an inline text body, so a body file can reference the incoming request (for example {{request.body}}) and use the response helpers. In the JMS mapping editor a file-backed response shows a read-only Response from file: note and loads the file's contents into the editable response body field; saving writes your edit back to the file and keeps the bodyFileName reference, so the body stays in the file rather than being copied inline. Exporting a scenario bundles the referenced body file, so file-backed JMS mappings round-trip through import and export. File message mappings can reference a response body file in exactly the same way. Native IBM® MQ mappings cannot: bodyFileName is not part of the IBM® MQ response format, so an IBM® MQ response body stays inline. Support for binary (bytes) response bodies read from a file will follow. See Response body from a file on the JMS page.
  • A gRPC request body matcher can now read the value it matches against from an external __files file through a bodyFileName reference: the same file-backed request body matcher already available for HTTP. Traffic Parrot resolves the file when the mapping loads and matches against its contents on replay exactly as it would an inline value, and the gRPC mappings list now shows the resolved file content (or, for a binary file, the matcher and the file path) in the Request message column instead of the raw bodyFileName reference. Editing a file-backed gRPC request matcher from the mapping editor is covered by the Switch to file and Switch to inline entry below.
  • The HTTP and gRPC mappings list now shows the matcher together with the bodyFileName path for a request body matcher whose value is read from a binary file (an image, PDF or other non-text file), for example binaryEqualTo 'payload.png', truncated to fit the column with the full path on hover, instead of a fixed placeholder that read the same for every binary file and so identified none of them. This applies to the HTTP Request body column, the gRPC Request message column and the rows' hover summaries, and it mirrors what the response body column already shows for a binary file-backed response body. Because the mappings list searches the text it displays, a mapping whose request body matcher is backed by a binary file can now also be found by typing the file name into the list search. A request body matcher backed by a text file still shows the file's content inlined, exactly as before.
  • A gRPC request payload can now be moved into, and out of, an external __files file from the mapping editor, rather than only by hand-editing the mapping JSON on disk. Opening a saved gRPC mapping whose request payload is inline shows a Switch to file button beneath the payload field; clicking it reveals a file name field pre-filled with a name derived from the mapping, and Save writes the payload to that file in __files and rewrites the matcher to the bodyFileName reference form. Re-opening the mapping shows a Content from file: note naming the file, loads the file's contents into the payload field so you can edit them in place, and offers Switch to inline to detach the reference and store the payload in the mapping again. A warning is shown when the file is shared with other mappings, because saving changes the request matcher for all of them. This matches what the HTTP editor already did, and the gRPC response body controls. The controls appear only for a mapping that has already been saved, and only for a single in-scope text matcher: a binary matcher or a request with several body patterns stays read-only in the editor, as on the HTTP form. Note that the file name may include forward-slash subdirectories, which resolve under __files, so requests/example.json is saved as __files/requests/example.json - the same as a response body file. A name that would resolve outside __files is rejected.
  • The request body Switch to file and Switch to inline controls in the mapping editor now cover three more request body matchers: matches JSON (matchesJson), matches GraphQL (matchesGraphQL) and matches JSON schema (matchesJsonSchema). Traffic Parrot already matched all three against a value read from an external __files file, but the editor did not offer to move one out to a file, so a large JSON body, GraphQL query or JSON Schema had to be externalised by hand-editing the mapping JSON on disk. This matters most in the gRPC editor, where matches JSON representation (matchesJson) is the matcher gRPC mappings most often use for the request payload. Saving keeps the matcher you chose rather than swapping it for equalToJson, so what the mapping matches is unchanged.
  • The Static Files page is now listed in the gRPC, JMS and Files menus, as it already was in the HTTP menu. All four entries open the same page, because __files is a single directory shared by every protocol within a scenario, so a file there can back a gRPC request payload, a gRPC response, a JMS or file-message response body, or an HTTP response equally. Previously the page could only be reached from the HTTP menu (or from the Manage files link in the gRPC response body area), which was easy to miss when working entirely in another protocol. The WebSocket and IBM® MQ menus deliberately do not carry the entry: those two do not resolve a bodyFileName, so the entry would advertise a capability they do not have.
  • Traffic Parrot now serves a Model Context Protocol (MCP) endpoint, so an AI assistant can connect to a running instance and read what it holds instead of working only from files you paste into the conversation. Traffic Parrot serves it itself, so there is nothing extra to install and no separate process to keep running: it listens on the management port (8080 by default) at /mcp and takes JSON-RPC 2.0 over HTTP POST, at the bare endpoint URL MCP clients are configured with rather than under /api. A connecting client completes the initialize handshake, which negotiates the protocol revision — the client is answered the revision it asked for when that is one Traffic Parrot speaks (2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05 or 2024-10-07), and the newest, 2025-11-25, when it asked for an unknown revision or for none at all — and which reports the instance's own version and its capabilities, and then lists twelve tools. Six only read — list_mappings, get_mapping, list_received_requests, report_coverage, list_scenarios and verify_mapping_matches — covering the mappings being served, the request journal, endpoint coverage, the defined scenarios, and whether received traffic still matches the mappings loaded now. The other six change something: create_mapping, update_mapping and delete_mapping change what the running instance serves and write the change through to the selected scenario's mapping files, so a scenario directory kept in version control will show it as a local change; select_scenario switches which scenario is being served, and so decides what every other tool reads and writes; generate_mappings_from_openapi builds mappings from a specification file already in the instance's OpenAPI directory, writing them through to the scenario's mapping files in the same way; and cleanup_mappings turns a recording into a flexible mock in a new scenario, leaving the recording untouched. Running a tool (tools/call) returns MCP content blocks, and only the advertised tools can be called. Every tool that can lose work takes dryRun, which defaults to true, so a call that does not say otherwise previews the change and tells the assistant how to commit it. A preview changes nothing in Traffic Parrot, but it is not inert: generate_mappings_from_openapi reads the specification file and fetches any externalValue example URL in it during a preview exactly as it does when applying. By default the endpoint accepts requests from the local machine only and needs no token; to reach it from elsewhere — notably Traffic Parrot in a container with a published port — set trafficparrot.mcp.authenticator=BEARER_TOKEN and trafficparrot.mcp.token, and send Authorization: Bearer <token>. Otherwise, anything that can reach the management port can reach this endpoint, so run Traffic Parrot on your own machine or a trusted network. Switching on the web UI login (trafficparrot.gui.security.mode=LOGIN_PROPERTIES) covers /mcp as well, so the client must then also send the HTTP BASIC credentials from trafficparrot.gui.login.properties; that refusal is an HTTP 401 whose JSON-RPC error names the login property and the credentials file, as against the HTTP 403 the MCP authenticator returns.
  • The HTTP Mapping cleanup results now name the mapping directories the cleaned scenario does not carry. Cleanup copies the source scenario's HTTP mappings and its __files directory and nothing else, so any JMS, native IBM® MQ, file message, gRPC or WebSocket mappings the scenario holds stay behind in the source scenario. That has always been the case, and it is deliberate (the cleanup conventions are HTTP conventions and have no meaning for a JMS or a gRPC mapping); what is new is that cleanup now tells you instead of leaving you to notice. A warning panel headed Mappings the cleaned scenario does not serve appears above the result counters with one entry per directory, naming it and the number of files that stayed behind, for example jms-mappings (3 file(s)) - not copied into the cleaned scenario. Nothing is lost: cleanup never modifies the source scenario, and the warning is there so the cleaned scenario is not mistaken for a complete replacement of the recording it came from and the other mappings dropped at the next promotion. Only a directory that actually holds files is listed, so an HTTP-only scenario shows no panel; the count is of files rather than mappings, because one mapping file can hold several mappings. The same list is returned by POST /api/http/cleanup/execute in a new droppedMappingDirectories field, and by the cleanup_mappings MCP tool, whose dryRun preview reports the same entries a real run would. It is a warning rather than an error: the cleanup succeeded and the errors field stays empty. See What the cleaned scenario does not carry.
  • A JMS request body matcher can now read the value it matches against from an external __files file through a bodyFileName reference, the messaging counterpart of the HTTP and gRPC file-backed request matchers. Traffic Parrot resolves the file when the mapping loads and matches against its contents on replay exactly as it would an inline value, so a large expected payload can live in a file beside the mapping instead of inside it. Exporting a scenario bundles the files referenced by request matchers as well as those referenced by response bodies, so a file-backed matcher round-trips through import and export. A bodyFileName is supported only on a matcher at the top level of the request: nesting one inside an and, or or not operator is refused when the mapping loads, with an error naming the mapping and the matcher. Native IBM® MQ and file-message request matchers keep their expected values inline.
  • Traffic Parrot now publishes the JSON Schemas that describe its own mapping formats, served from the management port (8080 by default), so a tool — or an AI coding agent — can fetch them from the very instance it is targeting and check a mapping before loading it. /schemas/index.json is a machine-readable index with one entry per mapping format (HTTP, which also covers gRPC; JMS; native IBM® MQ; and file messages), each carrying that schema's URL, its version, and the directory the format's mapping files live in; the schemas themselves are served beside it, for example /schemas/http-mapping.schema.json. They ship inside Traffic Parrot, so they always describe the version you are actually running. Alongside them, /helper-policy.json publishes the Handlebars helper safety policy: which response-templating helpers are safe to use, and which are denied because they can run arbitrary code (executeProcess and evaluate). trafficparrot validate can enforce that policy as well as the schemas — set trafficparrot.validate.helper.policy.check and validation fails when a mapping uses a denied helper, which is worth switching on for mappings a machine wrote. See Point the agent at the mapping schema.

Documentation

  • Added a Generate mocks with your own AI agent recipe page. It shows how to have your own AI coding agent (Claude Code, Cursor, or any assistant that can fetch a URL and call an HTTP API) write Traffic Parrot mappings for you: ground the agent on the mapping JSON Schema and the helper policy your instance serves, plus your own API contract, have it check the mapping against the schema, then load it through the admin API. The page opens with a Claude Code quick start and a copy-paste starter prompt that runs end to end against the community Train Travel API sample, so you can try it as-is before swapping in your own contract. It also covers running on a trusted network, the Handlebars helper deny-list (helper-policy.json) and its opt-in trafficparrot.validate.helper.policy.check enforcement in trafficparrot validate, and why an API contract handed to a language model is untrusted input. The mapping-creation endpoints it uses are documented in the Management API specification.
  • Expanded the Management API documentation to cover ten more management endpoints: priming an HTTP mapping and downloading a file from the scenario's __files directory, exporting the HTTP mappings, listing the gRPC mappings, and listing, creating, editing and deleting JMS and native IBM® MQ mappings. Each carries its request and response shapes and the status codes it returns, including the HTTP 409 the JMS and native IBM® MQ endpoints return while the virtual service is running — stop it before adding, editing or deleting a mapping. The WireMock-compatible admin API continues to be covered by reference to WireMock's own API documentation rather than restated here, and the raw specification remains available to download.

Fixes

  • Saving a gRPC mapping with an empty or malformed method name (the package.Service/Method value) now reports a clear validation message instead of failing with an internal server error. In the gRPC Add/Edit mapping form an inline message, Enter a fully-qualified gRPC method as package.Service/Method, appears beneath the gRPC method field and blocks the save; the gRPC management API (POST /grpc/management/mapping and PUT /grpc/management/mapping/{id}) returns HTTP 400 with the same message instead of HTTP 500. Previously an empty or malformed method produced a raw HTTP 500 and stack trace. Mappings imported from an exported zip are unchanged.
  • The ActiveMQ internal broker no longer caps the TCP connection handshake allowance at 10 seconds. Traffic Parrot asks for 60 seconds when it connects to the internal broker, but the broker itself had never advertised a matching allowance, and the OpenWire protocol settles on the shorter of the two ends' values — so 10 seconds was always the limit in force, and a connection slow to complete its handshake (a heavily loaded machine, or many connections opening at once) could be dropped with an inactivity error. The broker now advertises the same 60 seconds, so Traffic Parrot's own connections get the allowance they ask for, and an application that configures a longer allowance on its own ActiveMQ client is no longer capped to 10 seconds by the internal broker. An application left on the ActiveMQ client default is unaffected. AMQP connections are unaffected — this applies to the TCP (OpenWire) transport only.
  • The target scenario name given to HTTP mapping cleanup must now be a name inside the instance's scenarios directory. Previously a name that resolved somewhere else — one climbing out of that directory with .., or an absolute path — was accepted, and the cleaned mappings were written to wherever it pointed. Such a name is now refused: the Cleanup page reports Target scenario '…' must be a name inside the scenarios directory instead of running, and POST /api/http/cleanup/execute returns HTTP 400 carrying the same message in its error field, instead of HTTP 200 after writing the mappings. An ordinary scenario name is unaffected and behaves exactly as before.
  • A request body matcher that reads its value from a file (a bodyFileName reference) must now name a file inside the mapping's __files directory. Previously a bodyFileName that resolved outside it, whether by climbing out with .. or by giving an absolute path, was accepted, and Traffic Parrot read that out-of-directory file and matched against its contents. Such a reference is now rejected when the mapping loads. An ordinary bodyFileName under __files is unaffected and behaves exactly as before.
  • Importing a zip of mappings now refuses any entry that would be written outside the directory being imported into. Previously an entry whose path climbed out with .. was extracted to wherever it pointed, so importing a zip from an untrusted source — which the admin GUI allows in a single click — could create or overwrite a file anywhere the Traffic Parrot process could write. Every file written during an import is now checked to be inside the target directory before it is created, and an entry that fails the check stops the import with an error naming it. An ordinary exported zip is unaffected and imports exactly as before.
  • Renaming a scenario now requires both the existing and the new name to be names inside the instance's scenarios directory. Previously a name that climbed out of that directory with .., or gave an absolute path, was accepted and the scenario directory was moved to wherever it pointed. Such a name is now refused, and a rename rejected for this or any other validation reason returns HTTP 412 carrying the reason instead of HTTP 500 and a stack trace. An ordinary scenario name is unaffected.
  • Importing a gRPC skeleton now refuses a file name that would resolve outside the scenario's gRPC mappings directory, instead of writing the generated mapping there.
  • A path that reads as being inside a permitted directory but points outside it through a symbolic link is now refused, where it was previously accepted. This applies wherever Traffic Parrot checks that a path stays inside a directory, including the mapping conflict preview.
  • The in-GUI configuration file editor now refuses a path that belongs to neither of the directories it manages, rather than falling through and editing it anyway.
  • The Static Files page now takes messaging mappings into account when it decides whether a file is still in use. Deleting or renaming a file referenced only by a JMS or file-message mapping was previously allowed without warning, because the check looked at HTTP and gRPC mappings only, and the mapping was left pointing at a file that no longer existed. The orphan badge now counts references from every protocol, so a file shown as orphaned really is unreferenced.
  • Two mappings can no longer be saved under the same mapping file name. A mapping's file is named after the mapping, so saving a second mapping whose name produces a file name already in use previously overwrote the first; such a save is now refused with a message asking you to rename the mapping, on the GUI, the admin API and the MCP tools alike. Mappings you already have are unaffected: importing and starting up are unchanged, so a scenario that already holds two mappings sharing a file name keeps loading exactly as before — what changes is that re-saving one of them from the editor now asks you to rename it first. The two shapes to expect are two mapping names that produce the same file name (orders/new and orders:new both become orders_new.json) and, on Linux, two names differing only in case. Relatedly, resetting the admin API while two mappings already shared a file name returned HTTP 500; it now completes.
  • Three fixes to the log viewer: the line-number gutter stays aligned with wrapped lines instead of drifting out of step with them; a log file with CRLF line endings no longer renders a stray carriage return in every line; and querying the configured log appenders returns an answer instead of throwing, so the viewer can report which files it is reading.
  • Exporting mappings to CSV no longer silently drops a mapping whose request-body matcher reads its expected body from an external file; it is exported with the rest.
  • Generating a mapping from a captured TEXT message that has no body no longer fails with an internal error.
  • Uploading a protoset file no longer poisons later gRPC proto scans: a bad upload is contained to that upload, instead of making every subsequent scan fail until Traffic Parrot is restarted.
  • Switch to file now reports why it cannot externalise a request body it does not support, instead of appearing to work and silently doing nothing.
  • A failed specification import now shows the reason the server gave, instead of the literal text undefined.
  • Importing an OpenAPI specification whose operation declares a response without content — a description but no content block, as is usual for a 204 No Content on a delete — now generates a mapping whose response has no body. Previously the generated response body was the literal text */*, a placeholder that leaked out of the example generator, and the mock then served that text to every matching call. A response that does declare content, including a declared */* media type carrying an example or a schema, is generated exactly as before. Upgrading does not rewrite mappings you already have; the change applies when a specification is imported, so re-importing the same specification regenerates such mappings without the placeholder body.
  • The file messaging page now reports a mappings-load failure instead of waiting indefinitely for mappings that will never arrive.
  • Property values that look like secrets are now redacted in the configuration Traffic Parrot writes to its log at startup, instead of being logged verbatim.

Monday, 20 July 2026

Traffic Parrot 5.61.0 released, what's new?

We have just released version 5.61.0. Here is a list of the changes that came with the release:

Features

  • Added the ability to import an AsyncAPI specification to create messaging mappings automatically — the messaging counterpart of importing an OpenAPI specification for HTTP. Go to JMS or IBM® MQ in the top navigation bar and click Import AsyncAPI, then upload a JSON or YAML AsyncAPI 2.x or 3.0 document. Traffic Parrot parses the document's channels and operations and shows a preview of one mapping per importable operation (destination, queue/topic type, operation id, the example payload generated from the message schema, and a duplicate-status badge); you select exactly which operations to import with per-row checkboxes and an Import Selected count. A malformed, unsupported, or empty document reports a clear error and creates nothing. Each selected operation becomes a mapping — a JMS mapping from the JMS page or a native IBM® MQ mapping from the IBM® MQ page — that serves the generated example payload, ready to refine in the editor. Both AsyncAPI 2.x and AsyncAPI 3.0 documents are supported with the JMS and IBM® MQ channel bindings; for a 3.0 document the destination is taken from the channel's address (falling back to the channel name). Both one-way send/receive operations and request-reply operations (those carrying an AsyncAPI 3.0 reply object) are imported: a request-reply operation receives the request on the operation's own channel and publishes the reply message's example on the reply channel's destination, shown in a Reply destination column in the preview. Other bindings (AMQP, Kafka, MQTT) and AsyncAPI 4.x are not yet supported, and advanced JSON Schema draft 2020-12 constructs that cannot yet be turned into an example render a placeholder payload.
  • The headless trafficparrot validate command now also checks your messaging mappings against your imported AsyncAPI specifications, so a partially-mocked messaging API cannot silently drift from its contract — the messaging counterpart of the OpenAPI (HTTP) and proto (gRPC) coverage checks. It enumerates the operations declared in the AsyncAPI specifications under <files-root>/asyncapi/ and reports any declared operation that has no backing JMS, native IBM® MQ or file-message mapping, for example No mapping covers AsyncAPI operation: QUEUE:orders. Operations are matched to mappings by destination identity (TYPE:name, where TYPE is QUEUE or TOPIC); for a request-reply operation coverage is measured on the inbound (request) destination only. Messaging drift participates in the same report and the same exit codes as the HTTP and gRPC checks (drift fails the build with exit code 1). Destinations you deliberately leave unmocked can be excluded with a messaging-coverage.properties file (key exclude.destinations) in the files-root, and a stale allowlist entry for a destination not present in any AsyncAPI specification is itself reported as drift. See Messaging coverage check on the JMS page.
  • The add/edit messaging-mapping editor now has a skeletons dropdown that pre-fills a messaging mapping form from an operation in an imported AsyncAPI specification — the messaging counterpart of the HTTP and gRPC skeletons dropdowns. Place AsyncAPI specifications (JSON or YAML, 2.x or 3.0) into the install's asyncapi/ directory (or use the import button beside the dropdown to upload one), then pick an operation: the form's destination name, destination type (Queue/Topic radio) and request body/payload pre-fill. For a request-reply operation the option is labelled <operationId> (request-reply) and pre-fills both the request side and the reply side (a cloned response row); a one-way operation pre-fills the request side only. The dropdown appears in both the JMS and native IBM® MQ messaging editors. See Messaging skeletons on the JMS page and on the IBM® MQ page.
  • Added the ability to import an async-message Pact contract as JMS or native IBM® MQ messaging stubs — the messaging counterpart of importing a Pact contract's HTTP interactions. Go to JMS or IBM® MQ in the top navigation bar and click Import message Pact, then upload a Pact .json file. Both contract shapes are detected automatically: a specification v3 contract's top-level messages[] array and a v4 contract's Asynchronous/Messages interactions[] (whose example body is read from the contents.content envelope). An HTTP-only contract is rejected with a message pointing you to the HTTP Pact import. Traffic Parrot shows a preview of one mapping per message interaction (destination, queue/topic type, the message description as the operation id, the example contents payload, and a duplicate-status badge); you select exactly which messages to import with per-row checkboxes and an Import Selected count. A file that is not valid JSON or has no message interactions reports a clear error and creates nothing. Each selected message becomes a one-way publish mapping — a JMS mapping or a native IBM® MQ mapping — that publishes the example payload on receipt of any message on its destination; Pact message interactions are fire-and-forget, so these are not request-reply stubs. Because a Pact message carries no destination, it is derived from the message's metadata (a destination, queue or topic key, where a topic key makes it a TOPIC) or, failing that, from the message's description; a description-derived destination raises a warning in the preview so you review it before importing. Import message Pact is licence-gated, available on a JMS or IBM® MQ licence respectively (the menu link does not appear without it). See Import a message Pact contract on the JMS page and on the IBM® MQ page.
  • You can now import a Pact contract (consumer-driven contract, specification v2, v3 and v4) as HTTP stubs. Upload the Pact .json file on the HTTP Import page exactly as you would any other format — Traffic Parrot detects it automatically (no format to choose) and turns each HTTP interaction into a stub mapping through the same preview, filter and select flow used for HAR and OpenAPI/Swagger. The request (method, path, query, headers, body) becomes the request matchers and the response (status, headers, body) becomes the stubbed response; JSON request bodies are matched tolerantly. For v4 contracts the Synchronous/HTTP interactions are imported (their bodies are read from the v4 body.content / body.contentType envelope); everything else is imported the same way as for v2 and v3. Pact matchingRules are honoured where they map onto Traffic Parrot's request matchers (request header and path regex, default JSON-body type matching); other rules fall back to an exact match and the import reports a warning listing them. This HTTP import handles HTTP interactions only — Pact message (asynchronous) interactions, including the Asynchronous/Messages interactions of a v4 contract, are imported separately as JMS or IBM® MQ messaging stubs (when a v4 contract mixes the two, the HTTP import brings in the HTTP interactions and skips the message ones with a warning). Response templating and provider verification / Pact Broker pull are not yet supported. See Importing Pact contracts.
  • You can now import an HTTP specification from a URL instead of downloading it to disk first. Paste a specification URL into the URL field on the HTTP Import page and click Fetch & preview; Traffic Parrot fetches the document server-side and feeds it into the same content-based import pipeline as an uploaded file, so Swagger/OpenAPI, HAR and Pact specifications can be imported by URL exactly as they are from a file, each shown in the same preview before importing. RAML and WireMock ZIP specifications cannot yet be imported from a URL and must be imported from disk. The feature is off by default and must be enabled by an administrator: set trafficparrot.http.importfromurl.enabled to true and list the hosts Traffic Parrot may fetch from in trafficparrot.http.importfromurl.allowedHosts, a default-deny allow-list (with the feature enabled but the allow-list empty, every fetch is refused). Because the fetch originates from the Traffic Parrot host, the feature is guarded against server-side request forgery (SSRF): allow-listed or not, a URL that resolves to a loopback, link-local, private or cloud-metadata address is rejected, DNS rebinding is guarded against, the scheme is restricted to http and https, and the response size and the connect and read timeouts are capped. See Importing from a URL.
  • Added the ability to export HTTP mappings as an OpenAPI 3.0 specification — the inverse of importing an OpenAPI specification. The active scenario's mappings are translated into OpenAPI paths and operations (grouping by path and method, normalising exact, templated and regular-expression URL matchers into OpenAPI paths, lifting query and header matchers into parameters, and emitting each response body as a literal example together with an inferred JSON schema for JSON bodies) and served off the existing export endpoint via a new ?format=openapi query parameter (GET /http/management/exportMappings?format=openapi), returning a YAML document (Content-Type: application/yaml) as openapi-<timestamp>.yaml; without the parameter the endpoint still returns the native WireMock ZIP unchanged. The same document can also be exported as JSON with ?format=openapi-json (Content-Type: application/json, downloaded as openapi-<timestamp>.json) — only the serialisation differs. The OpenAPI export can be triggered from the GUI with the Export as OpenAPI (YAML) button on the HTTP Export page (alongside the existing Download Mappings button) as well as programmatically through the endpoint. Matchers with no clean OpenAPI representation (regex/JSONPath/XPath body matchers, proxy responses) are never silently dropped — every mapping's disposition (REPRESENTED, APPROXIMATED or OMITTED) is recorded in a coverage report surfaced both as a root-level x-trafficparrot-export-coverage extension and as a one-line summary in info.description. For each JSON response body Traffic Parrot also infers a JSON schema and emits it alongside the example, so generated clients, SDK codegen and documentation portals get real models rather than just a sample value; inference is conservative and based on the single example body (structure followed recursively, integral numbers become integer and non-integral number, JSON null becomes nullable, observed keys become properties but none is marked required, and no enum is inferred). A non-JSON response body (XML, plain text, empty) gets no schema — the example is still emitted and the mapping is recorded in the coverage report with reason no-schema-inferred. This release is single-scenario and OpenAPI 3.0 (not 3.1), with no multi-example merge or security schemes yet.
  • Added the ability to export recorded HTTP traffic as a HAR 1.2 file, ready to drive a load or resilience test through your own engine. Unlike the native ZIP and OpenAPI exports, which export the deduplicated mappings, the HAR export is taken from the live request journal — the ordered, timed stream of inbound requests served during the current session — so the request order and per-request timing a load profile needs are preserved. Each request becomes one HAR log.entries entry carrying the method, URL, headers, query string and request body, the response status, headers and body, and startedDateTime / time. Click the new Download recorded traffic (HAR) button on the HTTP Export page (alongside Download Mappings and Export as OpenAPI (YAML)), or trigger it programmatically off the existing export endpoint with the ?format=har query parameter (GET /http/management/exportMappings?format=har), which returns a HAR 1.2 document (Content-Type: application/json) downloaded as recorded-traffic-<timestamp>.har; without the parameter the endpoint still returns the native WireMock ZIP unchanged. The exported HAR can be fed into the common HAR-to-load-test converters such as the Gatling HAR Converter or Grafana har-to-k6 (Traffic Parrot does not run the load itself — you supply the engine). The export reads the in-memory request journal, so only the most recent requests retained by trafficparrot.virtualservice.maxRequestJournalEntries (default 1000) are exported; if the journal is disabled (=0) the export is a valid but empty HAR. This first release exports text bodies for HTTP traffic only.
  • HAR import now offers explicit conflict resolution for duplicate entries. When a preview entry matches an existing stub with the same HTTP method and exact URL, an On duplicate dropdown on that row — and a single For duplicates: control that applies to every duplicate at once — lets you Skip it (the default, so imports you do not touch are unchanged), Overwrite the existing stub (all stubs matching that method and URL are removed before the imported one is added, so no duplicate is left behind), or Import as new (the existing stub is kept and the imported one is added under a disambiguated name such as <name> (copy)). A per-row choice overrides the bulk default. Re-importing the same file still replaces the mappings it created last time, so those entries show as New; the actions apply to a clash against a stub from a different import or one created by hand. The same choice is available on the REST import endpoint (POST /http/management/importSelectedEntries) through an optional conflict-strategy parameter (skip | overwrite | importAsNew, default skip) with per-entry conflictStrategies overrides; omitting the parameter keeps the previous behaviour. Duplicate detection is an exact method-and-URL match, so an existing stub that matches its URL by pattern or regular expression is not detected as a duplicate. See Preview and filter before importing.
  • The HTTP and gRPC mappings list now shows the bodyFileName path for a mapping whose response body is served from a binary file (an image, PDF or other non-text file), truncated to fit the column with the full path on hover, instead of an unreadable placeholder, so you can tell at a glance which mapping serves which file. When that binary file is an image (PNG, JPEG, GIF, WebP, BMP, ICO, APNG or AVIF), hovering the row pops a small rendered preview of the image in place of the file-path tooltip, so you can recognise the picture a mapping serves without opening the editor; the cell still shows the truncated bodyFileName path, the preview is loaded on first hover and capped to a thumbnail, and it falls back to the plain path tooltip if the image cannot be read. Non-image binary rows keep the full-path tooltip. Inline, recorded, and text file-backed responses show their body content in the Response body / Response message column as before. See File-backed responses in the mappings list.
  • The HTTP mappings list now shows a composite request body matcher — one built from the logical and, or or not operators — as a readable one-line summary in the Request body column, for example and (contains 'A', contains 'B') or not (equalTo 'X'), instead of the raw matcher JSON. The row's request-match hover tooltip (which already summarised the method, URL matcher, URL and query parameters) now also lists each request body matcher on its own Body: line. Simple (leaf) matchers such as equalTo and contains are shown exactly as before; this changes only how existing matchers are displayed — nothing about how requests are matched or how mappings are saved changes.
  • The HTTP Add/Edit mapping panel now shows a live, non-blocking warning beneath the URL match mode when you combine a full-URL match mode (equal to or matches regex) with one or more query parameter matchers — a combination that is almost always wrong, because those modes match the whole URL (including the query string) and conflict with the separate query parameter matchers. The warning explains the problem and recommends switching to a path-only mode (path equal to or path matches regex), and it appears and disappears as you change the URL mode or add and remove query parameter rows. Saving is not blocked.
  • The HTTP and gRPC Add/Edit mapping forms gained three improvements for working with a file-backed response. A Manage files link in the response body area opens the Static Files browser in a new browser tab, so you can manage the files a response is served from without leaving, or losing, the mapping you are editing; the link is always shown, whether the response is inline or already file-backed (previously the Static Files browser was reachable only from the HTTP menu). When the response is an image file (PNG, JPEG, GIF, SVG, WebP, BMP, ICO, APNG or AVIF) the form shows an inline preview of it above the Response from file note, so you can see at a glance which image a mapping serves without opening the file; the body field stays read-only for binary files as before, non-image binary files keep the read-only field with no preview, and this mirrors the inline image rendering already used in the Static Files browser preview pane. Clicking Switch to file now shows a Choose an existing file… dropdown beside the response body file name field, listing the files already in the scenario's __files directory (including nested responses/ files); selecting one fills the file name so you can point a response at an existing body file without typing the path, and typing the name by hand still works as before. See Editing a file-backed response in the UI.
  • The HTTP Mapping cleanup results now include a collapsible Per-endpoint detail view showing, per recorded endpoint, exactly what cleanup did to it (kept, consolidated, headers stripped, body match removed, URL pattern applied, response template added, or removed), plus a consolidation-groups breakdown of which recorded URLs collapsed into each surviving pattern. The /api/http/cleanup/execute response gains matching endpointDispositions and consolidationGroups fields.
  • The HTTP Add/Edit mapping editor's request body matcher dropdown now offers matches JSON schema, which was previously only usable by editing the mapping JSON directly — it matches when the request body is JSON that validates against the given JSON Schema. Enter the schema as the matcher value; it round-trips on save. The advanced JSON-only option (the JSON Schema schemaVersion dialect selector) remains available by editing the mapping JSON — see the JSON-only matchers reference.
  • The HTTP Add/Edit mapping editor's Request URL matcher dropdown now offers path template as a fifth URL match type, alongside equal to, matches regex, path equal to and path matches regex. Enter a URL path template with named variables such as /orders/{orderId}; a request path matches when it fits the template's shape regardless of the concrete variable values (so /orders/{orderId} matches /orders/123). It persists as the urlPathTemplate request field and round-trips on save. The matcher also appears in the editor's Available helpers panel under URL match types.
  • The HTTP Add/Edit mapping editor now also lets you edit request headers and response headers with per-header rows, using the same click-to-add-rows editing already offered for query parameters. A request header row carries a header name, a matcher dropdown (equal to, contains, matches regex, does not match regex, equal to date/time, before date/time and after date/time) and a value, because request headers are matched; a response header row has just a Name and a Value with no matcher dropdown, because response headers are static Name: value pairs the mock returns rather than request matchers. In both cases the free-text headers field is kept for bulk, copy-paste-friendly editing, and the rows and text area stay in two-way sync (most recent edit wins); click Add request header or Add response header to add a row and the trash button to remove one. The saved mapping JSON is unchanged (standard WireMock request and response headers), so existing mappings load back into both views and round-trip on save, no header-matching expressiveness is lost, and the gRPC and messaging editors are unchanged.
  • A file-backed request body matcher (one whose value is read from a bodyFileName file in __files) is now editable in the HTTP Add/Edit mapping editor, like a file-backed response: a Content from file note names the file, the request body field is pre-filled with its contents, and saving writes your edit back to the file (the matcher keeps its bodyFileName reference). A single file-backed text matcher also offers a Switch to inline button (mirroring the file-backed response control) that detaches the bodyFileName reference and keeps the loaded contents as an inline matcher value; on save the matcher is stored inline, with no __files reference and the file on disk left untouched. A binaryEqualTo matcher, or a mapping with more than one request body matcher, stays read-only, offers no Switch to inline, and is edited on disk. See Request body file: In the GUI.
  • The Available helpers panel is now also available on the gRPC mapping editor (gRPC » Add/Edit), as it already is on the HTTP and messaging editors. Expand the collapsible Available helpers card to browse, filter and copy the response-templating helpers and the request-body matchers that apply to a gRPC mapping, without leaving the editor.
  • HAR import now offers an opt-in Preserve full fidelity (all headers) mode. By default an imported stub stays flexible — it matches on method, URL and the request Content-Type, and its response carries only the status, body and Content-Type, with all other request and response headers dropped so the stub is not tied to the exact browser, session or environment that produced the recording. Tick the new Preserve full fidelity (all headers) checkbox next to Import Selected on the HAR import preview (off by default; a whole-import setting, not per-entry) to instead turn every recorded request header — including Content-Type — into an exact request matcher and emit every recorded response header (with the exact response Content-Type and charset) on the stub response. This produces a faithful reproduction of the recorded exchange but makes stubs strict and often single-use: headers such as Host, Cookie, Authorization and Content-Length tie the stub to a specific host, session, token or body, so leave it off for reusable stubs. HTTP/2 pseudo-headers (:method, :authority, :scheme, :path, :status) are automatically excluded. The same behaviour is available programmatically through an optional preserveAllHeaders parameter on the /http/management/importMappings and /http/management/importSelectedEntries REST endpoints. Request and response bodies import unchanged (base64-encoded bodies are decoded automatically), and the option affects HAR import only — OpenAPI, Swagger, RAML, Pact and WireMock ZIP imports are unaffected. See Preserve full fidelity (all headers).
  • HTTP recording gained two Advanced parameters options on the HTTP Record page for how bodies are stored, both off by default so existing recording workflows are unchanged. Keep valid-JSON response body inline keeps a recorded response body inline in the mapping (as a structured jsonBody) when it is valid JSON served with a text content type, instead of writing it to a separate __files/ body file, so a recorded JSON API produces self-contained mappings with no companion body files; non-JSON text bodies and binary bodies (including a binary content type whose bytes happen to parse as JSON) are still externalised to __files/ as before, and there is no size limit on inlining, so a very large JSON response is embedded directly in the mapping file. Externalise request body to file is the request-side counterpart of the response-side inline option, and the write-time counterpart of a file-backed request body matcher: it writes a recorded request body to a separate __files/ file, with the recorded mapping's request matcher carrying a bodyFileName reference (equalToJson, equalToXml, binaryEqualTo or equalTo according to the request's content type, a binary body written byte-for-byte) instead of an inline bodyPatterns value; empty and multipart request bodies are always kept inline, and an externalised request body loads, matches on replay, and is editable in the Add/Edit mapping editor exactly like a manually file-backed one. With Externalise request body to file off, recording produces byte-identical mappings. Set trafficparrot.http.recording.response.inlineJson or trafficparrot.http.recording.request.externaliseToFile in trafficparrot.properties to change the checkboxes' default states. See Keeping JSON response bodies inline and Externalising request bodies to files.
  • The URL contains filter on the HTTP import preview now supports glob wildcards — * for any sequence of characters and ? for any single character — in addition to plain substring matching. Plain text still matches any path that contains it; a pattern with a wildcard switches to an anchored, case-insensitive match against the request path (for example /api/*, *.json or /users/?). This filters which entries are shown for selection only and does not change how the imported stubs match at runtime (GitHub issue #68).
  • The admin request-journal endpoint (GET /api/http/requests) now accepts two optional query parameters for paging and filtering a large journal: limit bounds the response to the first N entries in journal order, and since returns only the requests recorded strictly after a given ISO-8601 timestamp (for example 2026-07-16T10:00:00Z); a negative limit or a malformed since is rejected with HTTP 400. Both are off by default, so a request with neither parameter still returns the whole journal unchanged, and the meta.total field continues to report the full count of everything recorded, independent of either parameter. See Page or filter the journal.

Documentation

  • Added a Recording HTTPS via the browser proxy section to the User Guide. It explains that Traffic Parrot records HTTPS by acting as a browser (forward) proxy: point your browser or application's proxy setting at Traffic Parrot, import the Traffic Parrot CA certificate (certificates/virtualservice-CA-keystore.p12, password trafficparrot, PKCS12) into the client's trust store, and Traffic Parrot mints a per-host certificate on the fly from the TLS SNI so it can decrypt and record traffic to any host. The Recording HTTP section links across to it.

Changes

  • The default in-memory request-journal retention has been lowered from 10000 to 1000 entries. The trafficparrot.virtualservice.maxRequestJournalEntries property bounds all request journals — HTTP, gRPC and JMS/IBM® MQ — so by default each now keeps the last 1000 requests (older entries age out as new requests arrive) instead of 10000. This keeps the default -Xmx128m install memory-safe under a sustained first-run/evaluation workload, where the oversized journal could otherwise exhaust the heap. If you need a longer request-log history, raise maxRequestJournalEntries in your trafficparrot.properties; the JVM heap setting (-Xmx128m) is unchanged.

Tuesday, 16 June 2026

Traffic Parrot 5.60.4 released, what's new?

We have just released version 5.60.4. Here is a list of the changes that came with the release:

Features

  • The HTTP Add/Edit mapping form now lets you edit a file-backed response (one served from a bodyFileName file) directly in the editor: a Response from file note above the response body field shows the file name, the body field is editable in place, and saving writes the edited content back to the body file in the __files directory through the mapping repository (so the in-memory cache stays in sync). When the same body file is shared by other mappings a warning is shown, because saving changes the response for all of them. You can flip a response between inline and file-backed in both directions — Switch to inline detaches the file and stores the body on the mapping, and Switch to file externalises an inline body to a new file under responses/ on save. Binary body files stay read-only and are edited on disk. Previously a file-backed response appeared as an empty body field with no indication it was served from a file.
  • The same file-backed response handling is now available on the gRPC Add/Edit mapping form: when a gRPC mapping's response is served from a response.bodyFileName file, a Response from file note shows the file name, the body field is editable in place and pre-filled from the __files directory, and saving writes the edited content back to the body file through the mapping repository. A warning is shown when the file is shared by other mappings, and you can flip a response between inline and file-backed in both directions (Switch to inline / Switch to file). Binary body files stay read-only.
  • Added support for externalising a request body matcher into a file in the __files directory via bodyFileName, mirroring the response-side bodyFileName convention. Any of the request body matchers (equalTo, equalToJson, equalToXml, binaryEqualTo, contains, doesNotContain, matches, doesNotMatch, matchesJsonPath, matchesXPath, matchesXml) can load the value it compares against from a file instead of inlining it in the mapping, resolved relative to the mapping's sibling __files directory and loaded once at mapping-load time. A file-backed matcher is shown in the HTTP Add/Edit mappings GUI with a Content from file note, and the mappings-list Request body column renders the matcher content inlined from the file. The externalised form is also accepted through the WireMock admin API (POST /__admin/mappings, PUT /__admin/mappings/{id} and POST /__admin/mappings/import): the file is resolved when the mapping is registered, a reference to a missing file is rejected at registration with HTTP 422 naming the file, combining bodyFileName with any other key in the same matcher entry is rejected, and mappings saved to disk keep the bodyFileName reference instead of the file's contents.
  • Added a Static Files browser under the HTTP menu that lists the active scenario's __files directory, marks each file as referenced or orphaned by cross-referencing the HTTP mappings, and previews a selected file's content (JSON and XML are pretty-printed; image files are rendered inline and other binary files show their content type and size). The browser also lets you:
    • Create a new text file under the __files directory directly from the admin UI: a New file affordance prompts for a relative file name and content and adds the file to the browser, where it appears with an orphaned badge until a mapping references it.
    • Edit a text file in place: selecting a non-binary file and clicking Edit replaces the preview with an editable text area and Save/Cancel buttons, and saving overwrites the file's content in the __files directory. When the file is referenced by one or more mappings (through response.bodyFileName) a warning is shown, because saving changes the response for all of them. Binary files remain read-only and are edited on disk.
    • Delete a file: each row has a Delete button that reveals an inline Confirm/Cancel step (no browser pop-up), and confirming the deletion of an unreferenced file removes it from disk and the row disappears. The delete is reference-safe — if the file still backs a mapping the deletion is refused, a banner lists the referencing mapping(s) and the file stays listed. The reference check is complete: it covers both a file used as an HTTP response body (response.bodyFileName) and a file used as a request body matcher, so a file that the browser's orphaned badge reports as unreferenced (the badge inspects only response references) can still be blocked from deletion when it is genuinely in use, protecting you from silently breaking a request matcher. Overriding the refusal is not currently supported; to delete a referenced file, first remove or repoint the mapping(s) that use it.
    • Rename a file within the __files directory: each row has a Rename button that reveals an inline editable target-name field with Confirm/Cancel (no browser pop-up). Renaming an unreferenced file moves it to the new name, creating any intermediate sub-directories the new name implies. Like delete, the rename is reference-safe — if the file still backs a mapping the rename is refused, a banner lists the referencing mapping(s) and the file keeps its old name, because renaming would leave the mapping pointing at a name that no longer exists. The reference check is complete in the same way: it covers both a file used as an HTTP response body (response.bodyFileName) and a file used as a request body matcher, so a file that the orphaned badge reports as unreferenced (the badge inspects only response references) can still be blocked from renaming when it is genuinely in use. Renaming onto a name that already exists is refused as well, so you never silently overwrite another file. To rename a referenced file, first remove or repoint the mapping(s) that use it; automatically updating the referencing mappings to the new name is not currently supported.
    • Upload an existing file into the __files directory straight from your browser: an Upload button next to New file opens a file picker, and the chosen file is uploaded and added to the browser. Both text and binary files are accepted — the bytes are stored verbatim, so an uploaded image is listed and rendered inline in the preview pane, and any other uploaded binary file is listed and shown with its content type and size. Uploading a file whose name already exists is refused so you never silently overwrite another file, and unsafe file names (for example an absolute path or one containing .. that would escape the scenario's __files directory) are rejected. The upload has a configurable size limit, set by the new trafficparrot.multipart.upload.max.size.mb property (default 10 MB, shared by all admin-UI file uploads); a file larger than the limit is rejected with HTTP 413 and the message File exceeds the maximum upload size of N MB shown in the upload form. The limit applies only to file uploads through the admin UI and does not affect recorded traffic or mapping sizes.
    • Resize the panes with a draggable divider between the file list and the preview, so you can widen either side to suit the file you are reading. Drag the divider to set the split (it stays between 20% and 80% so neither pane collapses), and double-click it to snap back to the default split. The split you choose is remembered in your browser across page reloads. On narrow screens the panes stack vertically as before.
    • Browse files as a directory tree: files in sub-directories of __files are now grouped under expandable folder rows instead of being listed by full relative path. Each folder shows a caret you can click to collapse or expand its contents (all folders are expanded by default), and each file is labelled by its own name and indented under its folder. Selecting a file previews it, and the referenced/orphaned badges and rename, delete, edit and upload actions all work exactly as before.
    • Preview images and other binary files: selecting an image file (PNG, JPEG, GIF, SVG, WebP, BMP, ICO, APNG or AVIF) now renders the image inline in the preview pane instead of the bare not previewable note, so you can see at a glance which image a mapping serves. Selecting any other binary file shows a Binary file — <content type>, <size> note (for example Binary file — application/octet-stream, 2.3 KB) instead, so you can tell its type and size without downloading it. Text, JSON and XML files are still pretty-printed and editable in place as before; images and other binary files remain read-only and are edited on disk. Image and binary files are served back for the preview with a nosniff content-type guard and as an attachment, so a file whose bytes happen to contain active content (such as a script-bearing SVG) can never run in your browser from the preview.
  • Added a Logging documentation page covering how to enable verbose logging, change the log level, find the log files (logs/trafficparrot.log), turn logging down or off, and use the Request Log near-miss view to see why an HTTP request did not match.
  • The HTTP mappings list now shows a Recording active banner above the table while a recording session is running, as a reminder that deleting a mapping while recording also stops that endpoint being re-recorded for the rest of the session.
  • The HTTP Record page now shows a Live coverage panel while a recording session is active, refreshing about once a second. It gives a running tally of the distinct endpoints seen so far — how many now have a mapping, how many were observed but are still unmapped, and how many mappings have not been observed — plus the per-endpoint observed and unmatched request counts, so you can tell during the session whether a recording has captured everything you expected. Endpoints are grouped by HTTP method and normalised path using the same convention as Mapping cleanup, and the panel notes how many requests in the request journal the tally is based on.
  • Added a Verifying requests guide for WireMock users, mapping the verify() DSL onto Traffic Parrot's request journal: assert a request was made, was made exactly N times, or was NOT made via POST /api/http/requests/count, inspect captured bodies via POST /api/http/requests/find, list unmatched requests and near misses, and reset the journal — with a WireMock-to-Traffic-Parrot translation table and copy-paste curl recipes.
  • The Application logs view (HTTP menu → Logs → Application logs) now offers a structured view of the server log in addition to the existing raw text view. The raw view remains the default; clicking Structured view parses each entry into its timestamp, level, thread and message, with a coloured band and a level badge (the level text is always shown, not signalled by colour alone, so the view stays readable in greyscale and for colour-blind users). Multi-line stack traces fold into a single collapsible entry (with Expand all / Collapse all), you can filter entries by level and by free text, and any line that does not match the log pattern is shown in full rather than hidden. The existing search, last-10,000-lines truncation and Download raw affordances are unchanged.
  • Added an Available helpers panel at form level — below both the request and response cards — on the HTTP and messaging (JMS, IBM MQ and file-message) Add/Edit mapping forms, so you can discover what Traffic Parrot offers without leaving the product. The collapsible, read-only panel is a sectioned shell with three catalogues: a Response templating helpers section listing the helpers grouped by category; a Request matchers section listing the available request matchers; and an Other functionality section covering Scenarios & state, Response delays, Fault simulation, response proxying, serving a response from a file, webhook callbacks and request-matching scripts. Each entry has a one-line description, a copy-ready snippet (already scaffolded with example parameters) and a docs link, with a filter box that narrows every section as you type (matching name and description) and a per-entry Copy button. It is discovery-only and does not change how mappings are saved or how responses are rendered.
  • The HTTP Add/Edit mapping form now lets you author the advanced response delay and fault shapes that were previously only configurable in mapping JSON: a log-normal random delay (median, sigma and an optional maximum, to model realistic response-time spread), a chunked dribble delay (split the response body into a number of chunks sent over a total duration, to simulate a slow trickle), and the CONNECTION_RESET_BY_PEER response fault. Because the editor now understands these shapes, opening and saving a WireMock-format JSON mapping in the GUI no longer silently strips them — previously a form open-save dropped a log-normal delayDistribution, a chunkedDribbleDelay or a CONNECTION_RESET_BY_PEER fault, so this also fixes that data loss.
  • Added a matches GraphQL request body matcher for stubbing a POST /graphql endpoint, where many operations share one URL. Its full-query form matches the request's query semantically — tolerant of insignificant whitespace, selection-set field order, and argument order, so differently formatted but equivalent queries select the same response (aliases and directives stay significant). Its object form matches on operationName alone to disambiguate operations on one URL, with an optional variables object to also assert on the request's variables. Select matches GraphQL in the Request body matcher dropdown on the HTTP Add/Edit mapping form to author the full-query form; the operation-name form is authored by importing mapping JSON. A request that is not valid GraphQL simply does not match (it is never an error), and a mapping whose own GraphQL query is invalid is rejected at save/import time.
  • Added a trafficparrot validate command that checks your mappings against their bound schemas without starting the server, for use as a continuous integration step. For HTTP it reports both schema drift (a mapping whose URL path and method are not declared in any OpenAPI specification in openapi/) and under-coverage (an operation declared in a specification that no mapping covers), so a partially-mocked API cannot silently drift from its contract; gRPC mappings are validated against their proto schema. It prints a labelled report and exits 0 (no drift), 1 (drift detected) or 2 (usage or configuration error, including a files-root with no mappings). Operations you deliberately do not mock can be excluded with an exclude.operations list in an openapi-coverage.properties file in the files-root; an allowlist entry that matches no operation in the specification is itself reported as drift so the list cannot quietly go stale.
  • Added an external-process HTTP response transformer that passes the response through a user-supplied executable (the "middleware") written in any language — familiar to Hoverfly users. For each matched request on an opted-in mapping, Traffic Parrot serialises a versioned JSON envelope (the matched request plus the response about to be sent) to the executable's stdin and applies the mutated response read back from stdout (status, headers, body); request mutation is not supported in this release. The feature is off by default (trafficparrot.http.externalprocess.enabled) and confined to a single operator-vetted directory (trafficparrot.http.externalprocess.allowedDir) — the executable runs as the Traffic Parrot OS user with no sandbox, so enable it only on trusted hosts. Each mapping configures the executable, optional args, a per-invocation timeoutMs (default 5000, the process is killed on expiry), and an onError fallback (fail-open returns the original response, fail-closed returns HTTP 500) applied on non-zero exit, timeout, malformed output, or a missing/disallowed executable.
  • The external-process transformer can now be enabled and configured directly in the HTTP mapping editor, instead of only by hand-editing the mapping JSON. When an operator has set trafficparrot.http.externalprocess.enabled=true, an ExternalProcessTransformer toggle appears in the Response transformers list under Advanced parameters; turning it on reveals an External Process tab in the Transformer parameters panel with structured fields for the executable, args (space or newline separated), timeoutMs, and onError (fail-open/fail-closed). The option is offered only when the feature is enabled, and selecting it does not bypass the trafficparrot.http.externalprocess.allowedDir allow-list that still gates which executables may run. Saving writes the same transformerParameters.external-process JSON the editor, the mapping file on disk, and the WireMock Admin API all share. See Configuring it in the editor GUI.

Documentation

  • Added an Environment variables in responses how-to page covering the {{systemValue}} Handlebars helper: reading an environment variable (type='ENVIRONMENT') or a JVM system property (type='PROPERTY') into a response body or header, the default= fallback, the wiremock* allow-list and the [ERROR: Access to … is denied] failure mode, and the underscore-vs-dot naming rule for environment variables.
  • Added a CORS for stub responses how-to answering the common WireMock “CORS not working” question. It documents that the Traffic Parrot virtual service is CORS-friendly out of the box for every path — the browser CORS preflight (OPTIONS) is auto-answered HTTP 200 with Access-Control-Allow-Methods, Access-Control-Allow-Headers and Access-Control-Max-Age, and the request Origin is reflected into Access-Control-Allow-Origin on the actual response — with no flag and no per-stub configuration (unlike WireMock's off-by-default --enable-stub-cors). It also shows how to pin a specific origin by setting Access-Control-Allow-Origin in a stub's response.headers, and clarifies that this CORS behaviour is independent of the trafficparrot.http.optionsResponse.enabled property (which emits only an Allow header).
  • Expanded the JVM arguments section of the User Guide with a full reference for the jvm.args file: where it lives in the install directory, how each non-empty line is passed to the server JVM at startup, a table describing every shipped default (including -Xmx128m, the line to raise for large recordings or datasets), and typical adjustments.

Fixes

  • Binary bodyFileName responses (images, PDFs, etc.) are now served byte-for-byte unchanged when HTTP Handlebars is enabled (the default, trafficparrot.http.handlebars.enabled=true) — no per-mapping configuration required (fixes a corruption where binary files served via bodyFileName were re-encoded as text). See Response body files: templating vs byte-for-byte.
  • Whether a bodyFileName response is templated or served byte-for-byte is now decided by positive binary evidence (the response Content-Type or the file extension): recognised binary types are served byte-for-byte; everything else is run through Handlebars. This also ensures text/template body files with no Content-Type are still rendered.
  • The Duplicate and Delete buttons in the gRPC mappings list work again — a regression had stopped them working, so a gRPC mapping could not be duplicated or deleted from the admin UI. Both actions now behave as they do for HTTP mappings.
  • A stub configured with the INCORRECT_SMALL_CONTENT_LENGTH response fault now injects the fault correctly — it serves the stubbed status with a too-small Content-Length header and a body truncated to that length — instead of returning an HTTP 500 error.
  • File-message mappings now honour the priority field when resolving match precedence. Previously, when two file-message mappings both matched an inbound message, priority was ignored and the mapping loaded first always won; HTTP, JMS and IBM MQ mappings already honoured priority correctly.
  • Library upgrades to fix OWASP issues.

Changes

  • When the external-process transformer is enabled, Traffic Parrot now validates the trafficparrot.http.externalprocess.allowedDir directory once at startup and logs a warning if it is empty, does not exist, is not a directory, or is non-canonical, so a misconfigured allow-list is surfaced at startup rather than at the first matched request. The check is warn-only — the server still starts.
  • The Import skeleton… upload on the HTTP and gRPC Add/Edit mapping pages (importing an OpenAPI/Swagger HTTP skeleton or a proto/descriptor-set gRPC message skeleton) now has a configurable size limit, set by the trafficparrot.multipart.upload.max.size.mb property (default 10 MB) — the same property that caps the Static Files browser upload. A file larger than the limit is rejected with HTTP 413 and the message The uploaded file exceeds the maximum upload size of N MB shown in the import error area, instead of being buffered unbounded. Previously these imports had no size limit.
  • The HTTP Import mappings REST endpoint (/http/management/importMappings) now enforces the same trafficparrot.multipart.upload.max.size.mb cap (HTTP 413 on an oversize upload) as the skeleton-import and Static Files uploads. Previously this endpoint had no size limit.
  • Externalising an inline response body to a file with Switch to file on the HTTP and gRPC Add/Edit mapping forms now takes a single click. The one click makes the response body file-backed straight away — it reveals the (editable) file name field pre-filled with a suggested name, shows the Response from file note, and offers Switch to inline to revert — and clicking Save then writes the body to that file under __files. Previously a second click was needed to confirm the file name before saving would externalise. Clearing the file name field keeps the body inline.
  • Upgraded bundled JRE from 21.0.7 to 21.0.11