diff --git a/Dockerfile b/Dockerfile
index 4443e3f6..eb6c1a5a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -22,4 +22,4 @@ RUN npm run generate
ENV HOST 0.0.0.0
EXPOSE 3000
-CMD ["npm", "run", "start"]
+CMD ["npm", "run", "dev"]
diff --git a/components/http/http-body-parameters.vue b/components/http/http-body-parameters.vue
index 5dd52baa..e76e02cd 100644
--- a/components/http/http-body-parameters.vue
+++ b/components/http/http-body-parameters.vue
@@ -39,9 +39,12 @@
(rawInput = value)"
+ />
@@ -725,7 +656,6 @@ import parseTemplateString from "~/helpers/templating"
import { tokenRequest, oauthRedirect } from "~/helpers/oauth"
import { cancelRunningRequest, sendNetworkRequest } from "~/helpers/network"
import { fb } from "~/helpers/fb"
-import { getEditorLangForMimeType } from "~/helpers/editorutils"
import { hasPathParams, addPathParamsToVariables, getQueryParams } from "~/helpers/requestParams"
import { parseUrlAndPath } from "~/helpers/utils/uri"
import { httpValid } from "~/helpers/utils/valid"
@@ -897,6 +827,7 @@ export default {
canListParameters() {
return (
this.contentType === "application/x-www-form-urlencoded" ||
+ this.contentType === "multipart/form-data" ||
isJSONContentType(this.contentType)
)
},
@@ -1115,9 +1046,6 @@ export default {
this.$store.commit("setState", { value, attribute: "rawInput" })
},
},
- rawInputEditorLang() {
- return getEditorLangForMimeType(this.contentType)
- },
requestType: {
get() {
return this.$store.state.request.requestType
@@ -1314,7 +1242,10 @@ export default {
let environmentVariables = getEnvironmentVariablesFromScript(preRequestScript)
environmentVariables = addPathParamsToVariables(this.params, environmentVariables)
requestOptions.url = parseTemplateString(requestOptions.url, environmentVariables)
- requestOptions.data = parseTemplateString(requestOptions.data, environmentVariables)
+ if (!(requestOptions.data instanceof FormData)) {
+ // TODO: Parse env variables for form data too
+ requestOptions.data = parseTemplateString(requestOptions.data, environmentVariables)
+ }
for (let k in requestOptions.headers) {
const kParsed = parseTemplateString(k, environmentVariables)
const valParsed = parseTemplateString(requestOptions.headers[k], environmentVariables)
@@ -1370,13 +1301,19 @@ export default {
})
}
requestBody = requestBody ? requestBody.toString() : null
- if (this.files.length !== 0) {
+ if (this.contentType === "multipart/form-data") {
const formData = new FormData()
- for (let i = 0; i < this.files.length; i++) {
- let file = this.files[i]
- formData.append(i, file)
+ for (const bodyParam of this.bodyParams.filter((item) =>
+ item.hasOwnProperty("active") ? item.active == true : true
+ )) {
+ if (bodyParam?.value?.[0] instanceof File) {
+ for (const file of bodyParam.value) {
+ formData.append(bodyParam.key, file)
+ }
+ } else {
+ formData.append(bodyParam.key, bodyParam.value)
+ }
}
- formData.append("data", requestBody)
requestBody = formData
}
// If the request uses a token for auth, we want to make sure it's sent here.
@@ -1645,19 +1582,6 @@ export default {
},
})
},
- prettifyRequestBody() {
- try {
- const jsonObj = JSON.parse(this.rawParams)
- this.rawParams = JSON.stringify(jsonObj, null, 2)
- let oldIcon = this.$refs.prettifyRequest.innerHTML
- this.$refs.prettifyRequest.innerHTML = this.doneButton
- setTimeout(() => (this.$refs.prettifyRequest.innerHTML = oldIcon), 1000)
- } catch (e) {
- this.$toast.error(`${this.$t("json_prettify_invalid_body")}`, {
- icon: "error",
- })
- }
- },
copyRequest() {
if (navigator.share) {
const time = new Date().toLocaleTimeString()
@@ -1689,7 +1613,9 @@ export default {
const deep = (key) => {
const haveItems = [...this[key]].length
if (haveItems && this[key]["value"] !== "") {
- return `${key}=${JSON.stringify(this[key])}&`
+ // Exclude files fro query params
+ const filesRemoved = this[key].filter((item) => !(item?.value?.[0] instanceof File))
+ return `${key}=${JSON.stringify(filesRemoved)}&`
}
return ""
}
@@ -1896,40 +1822,8 @@ export default {
}
this.setRouteQueryState()
},
- uploadAttachment() {
- this.filenames = ""
- this.files = this.$refs.attachment.files
- if (this.files.length !== 0) {
- for (let file of this.files) {
- this.filenames = `${this.filenames}
${file.name}`
- }
- this.$toast.info(this.$t("file_imported"), {
- icon: "attach_file",
- })
- } else {
- this.$toast.error(this.$t("choose_file"), {
- icon: "attach_file",
- })
- }
- },
- uploadPayload() {
- this.rawInput = true
- const file = this.$refs.payload.files[0]
- if (file !== undefined && file !== null) {
- const reader = new FileReader()
- reader.onload = ({ target }) => {
- this.rawParams = target.result
- }
- reader.readAsText(file)
- this.$toast.info(this.$t("file_imported"), {
- icon: "attach_file",
- })
- } else {
- this.$toast.error(this.$t("choose_file"), {
- icon: "attach_file",
- })
- }
- this.$refs.payload.value = ""
+ updateRawBody(rawParams) {
+ this.rawParams = rawParams
},
async handleAccessTokenRequest() {
if (this.oidcDiscoveryUrl === "" && (this.authUrl === "" || this.accessTokenUrl === "")) {
diff --git a/plugins/vuex-persist.js b/plugins/vuex-persist.js
index c834193f..0dd9869a 100644
--- a/plugins/vuex-persist.js
+++ b/plugins/vuex-persist.js
@@ -1,5 +1,7 @@
import VuexPersistence from "vuex-persist"
export default ({ store }) => {
- new VuexPersistence().plugin(store)
+ new VuexPersistence({
+ filter: (mutation) => mutation.type !== "setFilesBodyParams",
+ }).plugin(store)
}
diff --git a/store/mutations.js b/store/mutations.js
index aa692673..ad5f37b4 100644
--- a/store/mutations.js
+++ b/store/mutations.js
@@ -107,6 +107,18 @@ export default {
request.bodyParams[index].value = value
},
+ // While this mutation is same as the setValueBodyParams above, it is excluded
+ // from vuex-persist. We will commit this mutation while adding a file
+ // param as there is no way to serialize File objects and thus we cannot
+ // persist file objects in localStorage
+ setFilesBodyParams({ request }, { index, value }) {
+ request.bodyParams[index].value = value
+ },
+
+ removeFile({ request }, { index, fileIndex }) {
+ request.bodyParams[index].value.splice(fileIndex, 1)
+ },
+
setActiveBodyParams({ request }, { index, value }) {
if (!request.bodyParams[index].hasOwnProperty("active")) {
Vue.set(request.bodyParams[index], "active", value)
diff --git a/store/postwoman.js b/store/postwoman.js
index 4f055bcb..760398f9 100644
--- a/store/postwoman.js
+++ b/store/postwoman.js
@@ -264,7 +264,15 @@ export const mutations = {
},
saveRequestAs({ collections }, payload) {
- const { request, collectionIndex, folderName, requestIndex } = payload
+ let { request, collectionIndex, folderName, requestIndex } = payload
+
+ // Filter out all file inputs
+ request = {
+ ...request,
+ bodyParams: request.bodyParams.map((param) =>
+ param?.value?.[0] instanceof File ? { ...param, value: "" } : param
+ ),
+ }
const specifiedCollection = collectionIndex !== undefined
const specifiedFolder = folderName !== undefined