SOAP/WSDL Mocking
SOAP mocking enables you to create mock SOAP/XML web service endpoints for testing enterprise integrations and legacy systems. Configure WSDL-based services with operation mocking, XPath request matching, and SOAP fault handling.
Overview
Section titled “Overview”mockd’s SOAP support includes:
- WSDL support - Define services inline or from external WSDL files
- Operation mocking - Return mock responses for SOAP operations
- XPath matching - Conditional responses based on request content
- SOAP faults - Return fault responses for error testing
- Namespace handling - Full XML namespace support
- Template support - Dynamic responses with variables
- Automatic WSDL serving - WSDL endpoint at
?wsdlsuffix
Quick Start
Section titled “Quick Start”Create a minimal SOAP mock:
version: "1.0"
mocks: - id: my-soap-service name: User Service type: soap enabled: true soap: path: /soap/UserService wsdl: | <?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://example.com/user" targetNamespace="http://example.com/user"> <message name="GetUserRequest"> <part name="userId" type="xsd:string"/> </message> <message name="GetUserResponse"> <part name="user" type="tns:User"/> </message> <portType name="UserPortType"> <operation name="GetUser"> <input message="tns:GetUserRequest"/> <output message="tns:GetUserResponse"/> </operation> </portType> </definitions>
operations: GetUser: soapAction: "http://example.com/GetUser" response: | <GetUserResponse xmlns="http://example.com/user"> <User> <Id>123</Id> <Name>John Doe</Name> <Email>john@example.com</Email> </User> </GetUserResponse>Start the server and test:
# Start mockdmockd serve --config mockd.yaml
# Call the SOAP servicecurl -X POST http://localhost:4280/soap/UserService \ -H "Content-Type: text/xml" \ -H "SOAPAction: http://example.com/GetUser" \ -d '<?xml version="1.0"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetUser xmlns="http://example.com/user"> <UserId>123</UserId> </GetUser> </soap:Body></soap:Envelope>'
# Get the WSDLcurl http://localhost:4280/soap/UserService?wsdlConfiguration
Section titled “Configuration”Full Configuration Reference
Section titled “Full Configuration Reference”mocks: - id: soap-service name: My SOAP Service type: soap enabled: true soap: # Endpoint path (required) path: /soap/MyService
# WSDL definition - use either inline or file wsdl: | <?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://schemas.xmlsoap.org/wsdl/"> ... </definitions> # OR wsdlFile: ./wsdl/service.wsdl
# Operation configurations operations: OperationName: soapAction: "http://example.com/OperationName" response: | <OperationNameResponse>...</OperationNameResponse> delay: "100ms" match: xpath: "//ElementName/text()": "value" fault: code: soap:Client message: "Error message" detail: "<ErrorCode>...</ErrorCode>"Configuration Fields
Section titled “Configuration Fields”| Field | Type | Description |
|---|---|---|
path | string | SOAP endpoint path (e.g., /soap/UserService) |
wsdl | string | Inline WSDL definition |
wsdlFile | string | Path to external WSDL file |
operations | map | Operation configurations by operation name |
Operation Fields
Section titled “Operation Fields”| Field | Type | Description |
|---|---|---|
soapAction | string | SOAPAction header value for matching |
response | string | XML response body |
delay | string | Response delay (e.g., "100ms", "2s") |
match | object | XPath-based request matching |
fault | object | SOAP fault response configuration |
WSDL Configuration
Section titled “WSDL Configuration”Inline WSDL
Section titled “Inline WSDL”Define the WSDL directly in your config:
soap: path: /soap/OrderService wsdl: | <?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://example.com/orders" targetNamespace="http://example.com/orders" name="OrderService"> <types> <xsd:schema targetNamespace="http://example.com/orders"> <xsd:element name="GetOrder"> <xsd:complexType> <xsd:sequence> <xsd:element name="orderId" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> </types> <message name="GetOrderInput"> <part name="parameters" element="tns:GetOrder"/> </message> <message name="GetOrderOutput"> <part name="parameters" element="tns:GetOrderResponse"/> </message> <portType name="OrderPortType"> <operation name="GetOrder"> <input message="tns:GetOrderInput"/> <output message="tns:GetOrderOutput"/> </operation> </portType> <binding name="OrderBinding" type="tns:OrderPortType"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="GetOrder"> <soap:operation soapAction="http://example.com/GetOrder"/> </operation> </binding> <service name="OrderService"> <port name="OrderPort" binding="tns:OrderBinding"> <soap:address location="http://localhost:4280/soap/OrderService"/> </port> </service> </definitions>External WSDL File
Section titled “External WSDL File”Reference an external WSDL file:
soap: path: /soap/OrderService wsdlFile: ./wsdl/orders.wsdlThe WSDL is served at http://localhost:4280/soap/OrderService?wsdl regardless of whether it’s inline or from a file.
Operations
Section titled “Operations”Operations define how each SOAP action is handled. Each operation maps a SOAPAction header to a response.
Basic Operation
Section titled “Basic Operation”operations: GetUser: soapAction: "http://example.com/GetUser" response: | <GetUserResponse xmlns="http://example.com/user"> <User> <Id>123</Id> <Name>John Doe</Name> <Email>john@example.com</Email> </User> </GetUserResponse>Multiple Operations
Section titled “Multiple Operations”operations: GetUser: soapAction: "http://example.com/GetUser" response: | <GetUserResponse xmlns="http://example.com/user"> <User> <Id>123</Id> <Name>John Doe</Name> </User> </GetUserResponse>
CreateUser: soapAction: "http://example.com/CreateUser" response: | <CreateUserResponse xmlns="http://example.com/user"> <UserId>{{uuid}}</UserId> <Status>Created</Status> <CreatedAt>{{now}}</CreatedAt> </CreateUserResponse>
DeleteUser: soapAction: "http://example.com/DeleteUser" response: | <DeleteUserResponse xmlns="http://example.com/user"> <Success>true</Success> </DeleteUserResponse>
ListUsers: soapAction: "http://example.com/ListUsers" response: | <ListUsersResponse xmlns="http://example.com/user"> <Users> <User><Id>1</Id><Name>Alice</Name></User> <User><Id>2</Id><Name>Bob</Name></User> <User><Id>3</Id><Name>Carol</Name></User> </Users> </ListUsersResponse>Response Delay
Section titled “Response Delay”Simulate slow backend services:
operations: GetReport: soapAction: "http://example.com/GetReport" delay: "2s" response: | <GetReportResponse xmlns="http://example.com/reports"> <Report> <Id>report_001</Id> <Status>Complete</Status> </Report> </GetReportResponse>XPath Matching
Section titled “XPath Matching”Use XPath expressions to match specific request elements and return conditional responses.
Basic XPath Match
Section titled “Basic XPath Match”operations: GetUser: soapAction: "http://example.com/GetUser" match: xpath: "//UserId/text()": "123" response: | <GetUserResponse xmlns="http://example.com/user"> <User> <Id>123</Id> <Name>John Doe</Name> <Email>john@example.com</Email> </User> </GetUserResponse>Multiple XPath Conditions
Section titled “Multiple XPath Conditions”Match on multiple elements simultaneously:
operations: SearchUsers: soapAction: "http://example.com/SearchUsers" match: xpath: "//Department/text()": "Engineering" "//Status/text()": "active" response: | <SearchUsersResponse xmlns="http://example.com/user"> <Users> <User><Name>Alice</Name><Department>Engineering</Department></User> <User><Name>Bob</Name><Department>Engineering</Department></User> </Users> </SearchUsersResponse>Conditional Responses with Multiple Mocks
Section titled “Conditional Responses with Multiple Mocks”Return different responses for different XPath matches by creating multiple mocks:
mocks: # Match user 123 - id: soap-user-123 type: soap enabled: true soap: path: /soap/UserService operations: GetUser: soapAction: "http://example.com/GetUser" match: xpath: "//UserId/text()": "123" response: | <GetUserResponse xmlns="http://example.com/user"> <User><Id>123</Id><Name>John Doe</Name></User> </GetUserResponse>
# Match user 456 - id: soap-user-456 type: soap enabled: true soap: path: /soap/UserService operations: GetUser: soapAction: "http://example.com/GetUser" match: xpath: "//UserId/text()": "456" response: | <GetUserResponse xmlns="http://example.com/user"> <User><Id>456</Id><Name>Jane Smith</Name></User> </GetUserResponse>
# Not found — no XPath match, acts as fallback - id: soap-user-not-found type: soap enabled: true soap: path: /soap/UserService operations: GetUser: soapAction: "http://example.com/GetUser" fault: code: soap:Client message: "User not found"XPath Patterns
Section titled “XPath Patterns”| Pattern | Description | Example |
|---|---|---|
//Element | Select element anywhere | "//UserId" |
/Root/Child | Absolute path | "/Envelope/Body/Request" |
//Element/text() | Element text content | "//UserId/text()" |
//Element[@attr] | Element with attribute | "//User[@active]" |
//Element[@attr='x'] | Specific attribute value | "//User[@type='admin']" |
Fault Responses
Section titled “Fault Responses”Return SOAP fault responses for error testing.
Basic Fault
Section titled “Basic Fault”operations: GetUser: soapAction: "http://example.com/GetUser" match: xpath: "//UserId/text()": "invalid" fault: code: soap:Client message: "Invalid user ID format"This generates:
<?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <soap:Fault> <faultcode>soap:Client</faultcode> <faultstring>Invalid user ID format</faultstring> </soap:Fault> </soap:Body></soap:Envelope>Fault with Detail
Section titled “Fault with Detail”Include structured error details:
operations: TransferFunds: soapAction: "http://example.com/TransferFunds" match: xpath: "//Amount/text()": "0" fault: code: soap:Client message: "Invalid transfer amount" detail: | <TransferError xmlns="http://example.com/errors"> <ErrorCode>INVALID_AMOUNT</ErrorCode> <MinAmount>0.01</MinAmount> <MaxAmount>1000000.00</MaxAmount> </TransferError>Server-Side Fault
Section titled “Server-Side Fault”Simulate backend failures:
operations: ProcessPayment: soapAction: "http://example.com/ProcessPayment" fault: code: soap:Server message: "Payment gateway unavailable" detail: | <ServiceError xmlns="http://example.com/errors"> <RetryAfter>30</RetryAfter> </ServiceError>Common SOAP Fault Codes
Section titled “Common SOAP Fault Codes”| Code | Description | Use Case |
|---|---|---|
soap:Client | Client-side error | Invalid request, missing data |
soap:Server | Server-side error | Internal errors, service unavailable |
soap:MustUnderstand | Header processing error | Required header not understood |
soap:VersionMismatch | SOAP version mismatch | Wrong SOAP version |
Dynamic Responses with Templates
Section titled “Dynamic Responses with Templates”Use template expressions in responses:
operations: CreateUser: soapAction: "http://example.com/CreateUser" response: | <CreateUserResponse xmlns="http://example.com/user"> <User> <Id>{{uuid}}</Id> <Name>New User</Name> <CreatedAt>{{now}}</CreatedAt> </User> </CreateUserResponse>Available templates:
| Template | Description |
|---|---|
{{uuid}} | Random UUID |
{{now}} | Current ISO timestamp |
{{timestamp}} | Unix timestamp |
Examples
Section titled “Examples”Payment Processing Service
Section titled “Payment Processing Service”version: "1.0"
mocks: - id: payment-soap name: Payment Service type: soap enabled: true soap: path: /soap/PaymentService operations: ProcessPayment: soapAction: "http://example.com/ProcessPayment" response: | <ProcessPaymentResponse xmlns="http://example.com/payment"> <TransactionId>{{uuid}}</TransactionId> <Status>APPROVED</Status> <Amount>99.99</Amount> <Currency>USD</Currency> <Timestamp>{{now}}</Timestamp> </ProcessPaymentResponse>
RefundPayment: soapAction: "http://example.com/RefundPayment" delay: "500ms" response: | <RefundPaymentResponse xmlns="http://example.com/payment"> <RefundId>{{uuid}}</RefundId> <Status>PROCESSED</Status> <Timestamp>{{now}}</Timestamp> </RefundPaymentResponse>
GetTransaction: soapAction: "http://example.com/GetTransaction" response: | <GetTransactionResponse xmlns="http://example.com/payment"> <Transaction> <Id>txn_001</Id> <Amount>99.99</Amount> <Currency>USD</Currency> <Status>COMPLETED</Status> <CardLast4>4242</CardLast4> <CreatedAt>2024-01-15T10:00:00Z</CreatedAt> </Transaction> </GetTransactionResponse>Weather Service with XPath Matching
Section titled “Weather Service with XPath Matching”version: "1.0"
mocks: - id: weather-soap-nyc name: Weather Service - NYC type: soap enabled: true soap: path: /soap/WeatherService operations: GetWeather: soapAction: "http://example.com/GetWeather" match: xpath: "//City/text()": "New York" response: | <GetWeatherResponse xmlns="http://example.com/weather"> <Weather> <City>New York</City> <Temperature>72</Temperature> <Unit>Fahrenheit</Unit> <Condition>Partly Cloudy</Condition> <Humidity>65</Humidity> </Weather> </GetWeatherResponse>
- id: weather-soap-london name: Weather Service - London type: soap enabled: true soap: path: /soap/WeatherService operations: GetWeather: soapAction: "http://example.com/GetWeather" match: xpath: "//City/text()": "London" response: | <GetWeatherResponse xmlns="http://example.com/weather"> <Weather> <City>London</City> <Temperature>18</Temperature> <Unit>Celsius</Unit> <Condition>Rainy</Condition> <Humidity>80</Humidity> </Weather> </GetWeatherResponse>
- id: weather-soap-default name: Weather Service - Default type: soap enabled: true soap: path: /soap/WeatherService operations: GetWeather: soapAction: "http://example.com/GetWeather" fault: code: soap:Client message: "City not found. Supported cities: New York, London"Enterprise Integration with Multiple Services
Section titled “Enterprise Integration with Multiple Services”version: "1.0"
mocks: - id: crm-soap name: CRM Service type: soap enabled: true soap: path: /soap/CRMService operations: GetCustomer: soapAction: "urn:crm:GetCustomer" response: | <GetCustomerResponse xmlns="urn:crm"> <Customer> <Id>CUST-001</Id> <Name>Acme Corp</Name> <Type>Enterprise</Type> <Status>Active</Status> <AccountManager>John Smith</AccountManager> </Customer> </GetCustomerResponse>
CreateLead: soapAction: "urn:crm:CreateLead" response: | <CreateLeadResponse xmlns="urn:crm"> <LeadId>{{uuid}}</LeadId> <Status>New</Status> <CreatedAt>{{now}}</CreatedAt> </CreateLeadResponse>
- id: inventory-soap name: Inventory Service type: soap enabled: true soap: path: /soap/InventoryService operations: CheckStock: soapAction: "urn:inventory:CheckStock" response: | <CheckStockResponse xmlns="urn:inventory"> <Item> <SKU>WIDGET-001</SKU> <InStock>true</InStock> <Quantity>250</Quantity> <Warehouse>US-EAST-1</Warehouse> </Item> </CheckStockResponse>
ReserveStock: soapAction: "urn:inventory:ReserveStock" delay: "200ms" response: | <ReserveStockResponse xmlns="urn:inventory"> <ReservationId>{{uuid}}</ReservationId> <Status>Reserved</Status> <ExpiresAt>{{now}}</ExpiresAt> </ReserveStockResponse>CLI Commands
Section titled “CLI Commands”Add a SOAP Mock
Section titled “Add a SOAP Mock”Create SOAP mocks directly from the command line using mockd soap add:
# Simple operationmockd soap add --path /soap/weather --action GetWeather \ --response '<Temp>72</Temp>'
# With a specific SOAPActionmockd soap add --path /soap/users --action GetUser \ --response '<User><Id>123</Id><Name>John</Name></User>'Output:
Created mock: soap_4b349e0c7719f577 Type: soap Path: /soap/weather Operation: GetWeatherAdd Command Flags
Section titled “Add Command Flags”| Flag | Description |
|---|---|
--path | SOAP endpoint path (required) |
--action | SOAP operation/action name (required) |
--response | XML response body |
--stateful-resource | Stateful resource name (e.g., users) |
--stateful-action | Stateful action: list, get, create, update, delete, custom |
--admin-url | Admin API URL (default: http://localhost:4290) |
Stateful SOAP via CLI
Section titled “Stateful SOAP via CLI”Wire a SOAP operation directly to a stateful resource from the command line:
# First, create a stateful resource (if one doesn't exist)mockd stateful add users
# Wire SOAP operations to the resourcemockd soap add --path /soap --action ListUsers --stateful-resource users --stateful-action listmockd soap add --path /soap --action GetUser --stateful-resource users --stateful-action getmockd soap add --path /soap --action CreateUser --stateful-resource users --stateful-action create--stateful-resource and --stateful-action must be used together. When set, the SOAP operation reads/writes from the named stateful resource instead of returning a canned response.
For complex SOAP mocks with WSDL definitions, XPath matching, or multiple operations, use a YAML config file instead of the CLI.
List SOAP Mocks
Section titled “List SOAP Mocks”# List all mocks (includes SOAP)mockd list
# Filter to SOAP mocksmockd list --type soap
# JSON outputmockd list --type soap --jsonDelete a SOAP Mock
Section titled “Delete a SOAP Mock”mockd delete soap_4b349e0c7719f577Testing
Section titled “Testing”Test with curl
Section titled “Test with curl”Basic SOAP request:
curl -X POST http://localhost:4280/soap/UserService \ -H "Content-Type: text/xml; charset=utf-8" \ -H "SOAPAction: http://example.com/GetUser" \ -d '<?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetUser xmlns="http://example.com/user"> <UserId>123</UserId> </GetUser> </soap:Body></soap:Envelope>'Verify WSDL Endpoint
Section titled “Verify WSDL Endpoint”# Fetch WSDLcurl http://localhost:4280/soap/UserService?wsdl
# Verify WSDL returns XMLcurl -sI http://localhost:4280/soap/UserService?wsdl | grep Content-Type# Content-Type: text/xml; charset=utf-8Test Fault Responses
Section titled “Test Fault Responses”Trigger a SOAP fault by sending a request that matches fault conditions:
curl -X POST http://localhost:4280/soap/UserService \ -H "Content-Type: text/xml" \ -H "SOAPAction: http://example.com/GetUser" \ -d '<?xml version="1.0"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetUser xmlns="http://example.com/user"> <UserId>invalid</UserId> </GetUser> </soap:Body></soap:Envelope>'
# Returns SOAP Fault with HTTP 500Test with SOAP Clients
Section titled “Test with SOAP Clients”mockd works with standard SOAP tools and libraries:
- SoapUI - Import the WSDL from
http://localhost:4280/soap/UserService?wsdl - Postman - Use SOAP request type with WSDL import
- Python zeep - Point to the WSDL endpoint
- .NET WCF - Add service reference using the WSDL URL
- Java JAX-WS - Generate client stubs from WSDL
Python zeep Example
Section titled “Python zeep Example”from zeep import Client
client = Client('http://localhost:4280/soap/UserService?wsdl')result = client.service.GetUser(UserId='123')print(result)Java Example
Section titled “Java Example”import javax.xml.ws.Service;import java.net.URL;import javax.xml.namespace.QName;
URL wsdlUrl = new URL("http://localhost:4280/soap/UserService?wsdl");QName serviceName = new QName("http://example.com/user", "UserService");Service service = Service.create(wsdlUrl, serviceName);UserPortType port = service.getPort(UserPortType.class);GetUserResponse response = port.getUser("123");Integration Tests (Go)
Section titled “Integration Tests (Go)”package main
import ( "bytes" "io" "net/http" "strings" "testing")
func TestSOAPMock(t *testing.T) { soapRequest := `<?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetUser xmlns="http://example.com/user"> <UserId>123</UserId> </GetUser> </soap:Body></soap:Envelope>`
req, _ := http.NewRequest("POST", "http://localhost:4280/soap/UserService", bytes.NewBufferString(soapRequest)) req.Header.Set("Content-Type", "text/xml; charset=utf-8") req.Header.Set("SOAPAction", "http://example.com/GetUser")
resp, err := http.DefaultClient.Do(req) if err != nil { t.Fatalf("Request failed: %v", err) } defer resp.Body.Close()
if resp.StatusCode != 200 { t.Errorf("Expected 200, got %d", resp.StatusCode) }
body, _ := io.ReadAll(resp.Body) if !strings.Contains(string(body), "John Doe") { t.Error("Response does not contain expected user name") }}Testing Tips
Section titled “Testing Tips”Verify SOAPAction Header Matching
Section titled “Verify SOAPAction Header Matching”SOAP mocks match on the SOAPAction header. Ensure your client sends it:
# This will matchcurl -X POST http://localhost:4280/soap/UserService \ -H "SOAPAction: http://example.com/GetUser" \ -H "Content-Type: text/xml" \ -d @request.xml
# This will NOT match (missing SOAPAction)curl -X POST http://localhost:4280/soap/UserService \ -H "Content-Type: text/xml" \ -d @request.xmlTest Error Handling
Section titled “Test Error Handling”Create mocks that return SOAP faults to verify your client’s error handling:
operations: # Timeout simulation SlowOperation: soapAction: "http://example.com/SlowOp" delay: "30s" response: | <SlowOpResponse><Status>done</Status></SlowOpResponse>
# Server error FailingOperation: soapAction: "http://example.com/FailOp" fault: code: soap:Server message: "Internal service error"Debug with Request Logs
Section titled “Debug with Request Logs”Use mockd’s request log to see incoming SOAP requests:
# View recent requestscurl http://localhost:4290/logs?limit=5
# Or via CLImockd logs --limit 5Use with CI/CD
Section titled “Use with CI/CD”Start mockd in the background for integration tests:
# Start in backgroundmockd start -d --config soap-mocks.yaml
# Run your SOAP client tests./run-soap-tests.sh
# Stop when donemockd stopStateful SOAP Operations
Section titled “Stateful SOAP Operations”SOAP operations can be wired to stateful CRUD resources, enabling shared state between REST and SOAP protocols. A REST POST /api/users creates a user that a SOAP GetUser can retrieve — and vice versa.
Configuration
Section titled “Configuration”Add statefulResource and statefulAction to any SOAP operation:
version: "1.0"
tables: - name: users seedData: - { id: "1", name: "Alice", email: "alice@example.com" }
mocks: - type: soap name: User SOAP Service soap: path: /soap/UserService operations: GetUser: soapAction: "http://example.com/GetUser" statefulResource: users statefulAction: get
ListUsers: soapAction: "http://example.com/ListUsers" statefulResource: users statefulAction: list
CreateUser: soapAction: "http://example.com/CreateUser" statefulResource: users statefulAction: create
UpdateUser: soapAction: "http://example.com/UpdateUser" statefulResource: users statefulAction: update
DeleteUser: soapAction: "http://example.com/DeleteUser" statefulResource: users statefulAction: deleteSupported Actions
Section titled “Supported Actions”| Action | Description | Request Data | Response |
|---|---|---|---|
get | Retrieve single item | ID extracted from XML | Item as XML |
list | List all items | Optional filters | Items wrapped in XML |
create | Create new item | Fields from XML body | Created item as XML |
update | Replace item (PUT) | ID + fields from XML | Updated item as XML |
patch | Partial update | ID + partial fields | Updated item as XML |
delete | Remove item | ID extracted from XML | Empty response |
custom | Multi-step operation | Defined by steps | Expression-built response |
How It Works
Section titled “How It Works”- SOAP request arrives and is routed to the matching operation
- XML body is parsed and converted to a
map[string]interface{} - The stateful Bridge executes the CRUD action against the shared store
- The result is converted back to XML and wrapped in a SOAP envelope
- Errors map to SOAP faults (e.g., not-found →
soap:Client)
Cross-Protocol State Sharing
Section titled “Cross-Protocol State Sharing”The key insight: stateful resources are protocol-agnostic. The same in-memory store backs both HTTP REST and SOAP:
# Create via RESTcurl -X POST http://localhost:4280/api/users \ -H "Content-Type: application/json" \ -d '{"name": "Alice"}'# → {"id": "abc-123", "name": "Alice", ...}
# Retrieve the same user via SOAPcurl -X POST http://localhost:4280/soap/UserService \ -H "SOAPAction: http://example.com/GetUser" \ -H "Content-Type: text/xml" \ -d '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body><GetUser><Id>abc-123</Id></GetUser></soap:Body> </soap:Envelope>'# → SOAP envelope with user dataWSDL Import
Section titled “WSDL Import”Generate SOAP mock configurations from existing WSDL files.
Using the SOAP Import Command
Section titled “Using the SOAP Import Command”# Basic import — generates static response mocksmockd soap import service.wsdl
# Stateful import — detects CRUD operations and wires to stateful resourcesmockd soap import service.wsdl --stateful
# Output to a specific filemockd soap import service.wsdl -o mocks.yaml
# Output as JSONmockd soap import service.wsdl --format jsonUsing the General Import Command
Section titled “Using the General Import Command”WSDL files are auto-detected by the general import command:
mockd import service.wsdlStateful Heuristics
Section titled “Stateful Heuristics”With the --stateful flag, the importer detects CRUD patterns in operation names:
| Pattern | Detected Action |
|---|---|
GetUser, FindOrder | get |
ListUsers, SearchOrders | list |
CreateUser, AddOrder | create |
UpdateUser, ModifyOrder | update |
DeleteUser, RemoveOrder | delete |
The importer generates both the statefulResources definitions and the SOAP operations with statefulResource/statefulAction fields pre-filled. For new projects, consider converting the generated statefulResources to tables and extend bindings for a cleaner separation of data and routing.
Custom Operations
Section titled “Custom Operations”Custom operations compose multiple reads, writes, and expression-evaluated transforms against stateful resources. This enables complex mock scenarios like fund transfers.
Configuration
Section titled “Configuration”customOperations: - name: TransferFunds consistency: atomic steps: - type: read resource: accounts id: "input.sourceId" as: source - type: read resource: accounts id: "input.destId" as: dest - type: update resource: accounts id: "input.sourceId" set: balance: "source.balance - input.amount" - type: update resource: accounts id: "input.destId" set: balance: "dest.balance + input.amount" response: status: '"completed"' newSourceBalance: "source.balance - input.amount" newDestBalance: "dest.balance + input.amount"Referencing from SOAP
Section titled “Referencing from SOAP”operations: TransferFunds: soapAction: "http://example.com/TransferFunds" statefulResource: TransferFunds # Name of the custom operation statefulAction: customManaging Custom Operations via CLI
Section titled “Managing Custom Operations via CLI”Custom operations can also be managed and executed directly from the CLI — useful for testing, scripting, and AI agent workflows:
# Validate before registering (optional but recommended)mockd stateful custom validate --file transfer.yaml --check-resourcesmockd stateful custom validate --file transfer.yaml \ --input '{"sourceId":"acct-1","destId":"acct-2","amount":100}' \ --check-expressions-runtime \ --fixtures-file transfer-fixtures.json
# Register a custom operation from a YAML filemockd stateful custom add --file transfer.yaml
# Or inline as JSONmockd stateful custom add --definition '{"name":"TransferFunds","steps":[...]}'
# List registered operationsmockd stateful custom list
# Execute directly (no HTTP/SOAP request needed)mockd stateful custom run TransferFunds --input '{"sourceId":"acct-1","destId":"acct-2","amount":100}'
# Wire to an HTTP endpoint toomockd http add -m POST --path /api/transfer --stateful-operation TransferFundsSee mockd stateful custom in the CLI reference for the full command set.
Step Types
Section titled “Step Types”| Step | Description |
|---|---|
read | Read an item from a resource, store in a named variable |
create | Create a new item in a resource |
update | Update an item using expression-evaluated fields |
delete | Delete an item from a resource |
set | Set a context variable to an expression result |
Expression Language
Section titled “Expression Language”Custom operations use expr-lang/expr for expressions. The environment includes:
input— the request data (parsed from SOAP XML, GraphQL variables, etc.)- Named variables from prior
readsteps (e.g.,source.balance) - All Go arithmetic, comparison, and string operators
Next Steps
Section titled “Next Steps”- Stateful Mocking - Complete stateful resource guide
- Response Templating - Dynamic response values
- Import/Export - Import existing SOAP mocks
- Chaos Engineering - Simulate failures
- Configuration Reference - Full configuration schema