specmatic
specmatic copied to clipboard
Specmatic Stub handling of binary responses (MimeType & Content)
Description I have an API that has application/pdf as return type for one of the endpoints. Currently, if i generate a stub from an interaction, i have no way to load bytes in the response (using externalValue). I can only type an inline string.
This has two effects:
- first i cannot correctly mock this interaction, because the calling app will need valid bytes to be sent back.
- second, the mime type sent back is incorrect, Specmatic looks at the pattern from the response example to generate the response. This means if Specmatic parses the example body as a StringValue, it will set the return MimeType to text/plain, which isn't compatible with the contract.
There are multiple behaviors that adds up to create the mimetype behaviour:
- Specmatic creates the example patterns from the example body, and doesn't look at the contract at all. This is why what is a "String format Binary" in the contract turns in a simple String in the example, generating the incorrect mimeType
- Specmatic doesn't use the contract at all for responses MimeTypes, just the Value class of the body
Steps to reproduce
1. Here's what you need, there is a contract, an interraction & 1 pdf files:
Contract:
openapi: 3.0.3
info:
contact:
url: http://balbala
title: GigaUpload Service
description: Service to upload things and break Specmatic :( sorry guyz
version: 1.0.0
servers:
- url: "http://{hostname}:{port}/{basePath}/"
variables:
hostname:
default: localhost
port:
default: "8080"
basePath:
default: rest
- url: "http://localhost:9000"
tags:
- name: UploadStuff
paths:
"/uploadstuff":
post:
tags:
- UploadStuff
operationId: UploadStuffToServer
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
uploadRequest:
$ref: "#/components/schemas/UploadRequest"
pdfFiles:
type: array
items:
type: string
format: binary
required:
- uploadRequest
- pdfFiles
encoding:
UploadRequest:
contentType: application/json
pdfFiles:
contentType: application/pdf
responses:
"200":
description: "The document has been sent successfully send and...we're sending it back, because reasons. You're not my dad."
content:
application/pdf:
schema:
type: string
format: binary
components:
schemas:
UploadRequest:
type: object
title: UploadRequest
properties:
name:
type: string
minLength: 1
maxLength: 255
coolNameYourFriendsGiveYou:
type: string
minLength: 1
maxLength: 255
required:
- name
- coolNameYourFriendsGiveYou
Interraction:
{
"http-request": {
"method": "POST",
"path": "/uploadstuff",
"multipart-formdata": [
{
"name": "pdfFiles",
"file": "(string)",
"filename": "%%changeme%%\\test.pdf",
"contentType": "application/pdf"
},
{
"name": "uploadRequest",
"content": {
"name": "Chris",
"coolNameYourFriendsGiveYou": "C-Dawg"
},
"contentType": "application/json"
}
]
},
"http-response": {
"status": 200,
"body": "feafaefaf"
}
}
PdfFile: test.pdf
Don't forget to update the file path in the interaction
2. Run specmatic in stub mode with the interaction loaded
3. Make a POST request to localhost:9000/uploadstuff of type multipart/form-data
The parts are:
- uploadRequest of type json:
{
"coolNameYourFriendsGiveYou": "C-Dawg",
"name": "Chris"
}
- pdfFiles: contains your test.pdf
Expected behavior I Expect the response to be of mimetype application/pdf like it's written in the contract. I Expect valid pdf bytes to be the body of the response
Screenshots
Response mimetype is text/plain:
System Information:
- OS & version: Windows 11
- Browser & version: Insomnia 2023
- Specmatic version: 0.77
- JDK version: OpenJDK 17
Additional context There are multiple ways we could solve these problems:
- Add support for externalValue in the responses
- At the OpenAPI parsing time (in OpenAPISpecification.kt) set the mimetype to the HttpResponsePattern from the contract and drop using the body value as MimeType source
This was hard to convey, let me know if something is not clear ! I will investigate the possible fixes that i talk about in the additional context. Please tell me what you think about them, how would you go about fixing this / adding this feature?
@aeoncl really appreciate the effort you have put into this detailed explanation. We'll read through it and get back to you.