Markdown Format Specification
Overview
proxymock creates files as artifacts when recording, replaying, and mocking. The RRPair markdown format is a human-readable representation of API traffic data used by Speedscale. This format allows developers and LLMs to easily read, understand, and modify API request/response data while maintaining all necessary technical details for accurate replay.
Key Benefits
- Human Readable: Easy to read and understand API interactions
- LLM Friendly: Structured format ideal for AI analysis and generation
- Round-trip Conversion: Lossless conversion between markdown and internal formats
- Version Control: Text-based format works well with git and diff tools
- Debugging: Simple format for troubleshooting API issues
File Structure
RRPair markdown files use section headers with the pattern ### SECTION_NAME ###
to organize content. The section ordering may change based on inbound or outbound traffic but that is only a convention and not a requirement:
### REQUEST (TEST) ###
### RESPONSE ###
### METADATA ###
### INTERNAL - DO NOT MODIFY ###
Section Specifications
REQUEST Section
The REQUEST section represents the HTTP request made to an API endpoint.
Format
### REQUEST (TEST) ###
METHOD PROTOCOL://HOST:PORT/PATH?QUERY HTTP/VERSION
Header-Name: Header-Value
Another-Header: value1, value2
Trailer: T1, T2, T3
T1: trailer-value-1
T2: trailer-value-2
T3: trailer-value-3
{
"request": "body content here"
}
Rules
- First Line: HTTP request line with method, full URL, and protocol version
- Headers: Listed alphabetically, case-sensitive
- Multi-value Headers: Joined with
,
(comma-space) - Trailer Headers: Listed after
Trailer:
header - Content-Length: Automatically calculated, excluded from display
- Body Separation: Empty line separates headers from body
- Body Formatting: JSON is pretty-printed, HTML is formatted
Example
### REQUEST (TEST) ###
POST https://api.example.com/v1/users HTTP/2.0
Authorization: Bearer eyJ0eXAiOiJKV1Q...
Content-Type: application/json
User-Agent: MyApp/1.0
{
"username": "john_doe",
"email": "john@example.com"
}
RESPONSE Section
The RESPONSE section represents the HTTP response from an API endpoint.
Format
### RESPONSE ###
Header-Name: Header-Value
Status-Header: status-value
{
"response": "body content here"
}
Rules
- Headers Only: No status line (status code stored in internal JSON)
- Alphabetical Order: Headers sorted alphabetically
- Content-Length: Excluded (recalculated during processing)
- Body Formatting: JSON pretty-printed, HTML formatted
- Empty Bodies: Represented as empty section
Example
### RESPONSE ###
Content-Type: application/json
Location: /users/12345
X-Request-ID: abc123
{
"id": 12345,
"username": "john_doe",
"email": "john@example.com",
"created_at": "2024-01-15T14:30:22Z"
}
RESPONSE (MOCK) Section
Used for outgoing traffic where the response is mocked.
Format
### RESPONSE (MOCK) ###
Content-Type: application/json
{
"mock": "response data"
}
Rules
- Same formatting rules as RESPONSE section
- Represents mock response for outgoing requests or expected response for inbound requests
SIGNATURE Section
The SIGNATURE section defines matching criteria for request replay.
Format
### SIGNATURE ###
key1 is value1
key2 is value2
key3 is -NONE-
Rules
- Format:
key is value
- Empty Values: Represented as
-NONE-
- Alphabetical Order: Keys sorted alphabetically
- Common Keys:
http:host
- Target hostnamehttp:method
- HTTP methodhttp:url
- URL pathhttp:queryparams
- Query parametersinstance
- Instance number for disambiguation
Example
### SIGNATURE ###
http:host is api.example.com
http:method is POST
http:queryparams is -NONE-
http:url is /v1/users
instance is 0
METADATA Section
Contains essential metadata about the request-response pair.
Format
### METADATA ###
direction: IN|OUT
uuid: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
ts: 2024-01-15T14:30:22.123456789Z
duration: 150ms
tags: key1=value1, key2=value2
Fields
- direction: Traffic direction (
IN
for incoming,OUT
for outgoing) - uuid: Unique identifier in standard UUID format
- ts: Timestamp in RFC3339Nano format (ISO 8601 with nanoseconds)
- duration: Request duration in milliseconds
- tags: Comma-separated key=value pairs for categorization
Example
### METADATA ###
direction: IN
uuid: f3ead946-90b1-43ab-a7d6-be3f799e8e83
ts: 2024-01-15T14:30:22.489942Z
duration: 155ms
tags: environment=staging, service=user-api, test_case=registration
INTERNAL Section
Contains the complete JSON representation of the RRPair for system use.
Format
### INTERNAL - DO NOT MODIFY ###
json: {"msgType":"rrpair","ts":"2024-01-15T14:30:22.489942Z",...}
Rules
- Single Line: Entire JSON object on one line
- Base Truth: Used as foundation during decoding
- Override: Other sections override specific fields
- No Manual Editing: Should not be modified by hand
- Base64 Encoding: Binary data encoded as base64 in JSON
Content Processing
JSON Bodies
- Pretty Printing: 2-space indentation for readability
- Compaction: Whitespace removed during decoding
- Auto-Detection: JSON content detected regardless of Content-Type
- Validation: Invalid JSON preserved as-is
HTML Bodies
- Formatting: Uses gohtml formatter for readability
- Minification: Whitespace optimized during decoding
- Content-Type Required: Must have Content-Type containing "html"
Binary Content
- Base64 Encoding: Binary data encoded in INTERNAL section
- Preservation: Original binary content maintained
- Display: May show as placeholder in markdown sections
Headers
- Sorting: Alphabetical by header name
- Case Preservation: Original case maintained
- Multi-value: Multiple values joined with
,
- Escaping: Commas escaped as
\,
, backslashes as\\
- Content-Length: Automatically excluded and recalculated
Complete Examples
Incoming API Request Example
### REQUEST (TEST) ###
POST https://api.payment.com/v1/charges HTTP/2.0
Authorization: Bearer sk_test_123456789
Content-Type: application/json
Idempotency-Key: charge_12345
{
"amount": 2000,
"currency": "usd",
"source": "tok_visa",
"description": "Test charge"
}
### RESPONSE ###
Content-Type: application/json
Request-ID: req_abc123def456
{
"id": "ch_1234567890",
"amount": 2000,
"currency": "usd",
"status": "succeeded",
"created": 1642176622
}
### METADATA ###
direction: IN
uuid: f3ead946-90b1-43ab-a7d6-be3f799e8e83
ts: 2024-01-15T14:30:22.489942Z
duration: 155ms
tags: service=payment, environment=test
### INTERNAL - DO NOT MODIFY ###
json: {"msgType":"rrpair","ts":"2024-01-15T14:30:22.489942Z","l7protocol":"http","duration":155,"tags":{"service":"payment","environment":"test"},"uuid":"8+rZRpCxQ6un1r4/eZ6Ogw==","direction":"IN","http":{"req":{"url":"/v1/charges","uri":"/v1/charges","version":"2.0","method":"POST","host":"api.payment.com","headers":{"Authorization":["Bearer sk_test_123456789"],"Content-Type":["application/json"],"Idempotency-Key":["charge_12345"]}},"res":{"contentType":"application/json","statusCode":200,"statusMessage":"200 OK","headers":{"Content-Type":["application/json"],"Request-ID":["req_abc123def456"]},"bodyBase64":"eyJpZCI6ImNoXzEyMzQ1Njc4OTAiLCJhbW91bnQiOjIwMDAsImN1cnJlbmN5IjoidXNkIiwic3RhdHVzIjoic3VjY2VlZGVkIiwiY3JlYXRlZCI6MTY0MjE3NjYyMn0="}}}
Outgoing API Request Example
### RESPONSE (MOCK) ###
Content-Type: application/json
X-API-Version: v1
{
"users": [
{
"id": 1,
"name": "John Doe",
"email": "john@example.com"
},
{
"id": 2,
"name": "Jane Smith",
"email": "jane@example.com"
}
],
"total": 2
}
### SIGNATURE ###
http:host is internal-api.company.com
http:method is GET
http:queryparams is limit=10&offset=0
http:url is /v1/users
instance is 0
### REQUEST ###
GET http://internal-api.company.com/v1/users?limit=10&offset=0 HTTP/1.1
Authorization: Bearer internal_token_123
User-Agent: MyService/2.1.0
### METADATA ###
direction: OUT
uuid: ba659889-6d94-40f1-b49f-d78f38df7dbd
ts: 2024-01-15T14:31:25.250965Z
duration: 42ms
tags: service=user-api, call_type=internal
### INTERNAL - DO NOT MODIFY ###
json: {"msgType":"rrpair","ts":"2024-01-15T14:31:25.250965Z","l7protocol":"http","duration":42,"tags":{"service":"user-api","call_type":"internal"},"uuid":"umWYiW2UQPG0n9ePON99vQ==","direction":"OUT","http":{"req":{"url":"/v1/users","uri":"/v1/users?limit=10&offset=0","version":"1.1","method":"GET","host":"internal-api.company.com","headers":{"Authorization":["Bearer internal_token_123"],"User-Agent":["MyService/2.1.0"]}},"res":{"contentType":"application/json","statusCode":200,"statusMessage":"200 OK","headers":{"Content-Type":["application/json"],"X-API-Version":["v1"]},"bodyBase64":"eyJ1c2VycyI6W3siaWQiOjEsIm5hbWUiOiJKb2huIERvZSIsImVtYWlsIjoiam9obkBleGFtcGxlLmNvbSJ9LHsiaWQiOjIsIm5hbWUiOiJKYW5lIFNtaXRoIiwiZW1haWwiOiJqYW5lQGV4YW1wbGUuY29tIn1dLCJ0b3RhbCI6Mn0="}},"signature":{"http:host":"aW50ZXJuYWwtYXBpLmNvbXBhbnkuY29t","http:method":"R0VU","http:queryparams":"bGltaXQ9MTAmb2Zmc2V0PTA=","http:url":"L3YxL3VzZXJz","instance":"MA=="}}
Usage Guidelines
For Humans
- Focus on REQUEST, RESPONSE, and METADATA sections for understanding
- Use SIGNATURE section to understand request matching criteria
- INTERNAL section contains technical details but is not meant for manual editing
- Headers and bodies are formatted for readability
- Timestamps and UUIDs provide traceability
For LLMs
- Parse section headers (
### SECTION_NAME ###
) to identify content types - REQUEST and RESPONSE sections contain the actual API interaction data
- METADATA provides context about timing, direction, and categorization
- SIGNATURE section defines matching criteria for replay scenarios
- INTERNAL section contains complete technical representation
- Body content may be JSON (formatted) or other content types
- Headers are consistently formatted and sorted
For Tools and Scripts
- Use the INTERNAL section as the authoritative source
- Other sections provide human-readable overlays
- Round-trip conversion preserves all data
- Headers exclude Content-Length (recalculated automatically)
- JSON bodies are formatted for display, compacted for processing
Best Practices
- Don't Edit INTERNAL: The INTERNAL section should be treated as read-only (unless you are experienced with proxymock)
- Preserve Formatting: Maintain the section header format exactly
- Header Consistency: Keep headers alphabetically sorted
- Body Formatting: Let tools handle JSON/HTML formatting
- Metadata Accuracy: Ensure timestamps and UUIDs are valid
- Tag Organization: Use consistent tag naming conventions
- Signature Completeness: Include all necessary matching criteria