Merge pull request #603 from liyasthomas/feature/fast-url
Added regex to handle url parts
This commit is contained in:
399
pages/index.vue
399
pages/index.vue
@@ -37,143 +37,145 @@
|
||||
|
||||
<pw-section class="blue" :label="$t('request')" ref="request">
|
||||
<ul>
|
||||
<li>
|
||||
<label for="method">{{ $t("method") }}</label>
|
||||
<span class="select-wrapper">
|
||||
<v-popover>
|
||||
<input
|
||||
id="method"
|
||||
class="method"
|
||||
v-if="!customMethod"
|
||||
v-model="method"
|
||||
readonly
|
||||
/>
|
||||
<input v-else v-model="method" placeholder="CUSTOM" />
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'GET'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
GET
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'HEAD'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
HEAD
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'POST'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
POST
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'PUT'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
PUT
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'DELETE'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
DELETE
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'CONNECT'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
CONNECT
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'OPTIONS'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
OPTIONS
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'TRACE'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
TRACE
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'PATCH'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
PATCH
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = true
|
||||
method = 'CUSTOM'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
CUSTOM
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</span>
|
||||
</li>
|
||||
<div>
|
||||
<li>
|
||||
<label for="method">{{ $t("method") }}</label>
|
||||
<span class="select-wrapper">
|
||||
<v-popover>
|
||||
<input
|
||||
id="method"
|
||||
class="method"
|
||||
v-if="!customMethod"
|
||||
v-model="method"
|
||||
readonly
|
||||
/>
|
||||
<input v-else v-model="method" placeholder="CUSTOM" />
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'GET'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
GET
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'HEAD'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
HEAD
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'POST'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
POST
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'PUT'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
PUT
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'DELETE'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
DELETE
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'CONNECT'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
CONNECT
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'OPTIONS'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
OPTIONS
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'TRACE'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
TRACE
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = false
|
||||
method = 'PATCH'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
PATCH
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="
|
||||
customMethod = true
|
||||
method = 'CUSTOM'
|
||||
"
|
||||
v-close-popover
|
||||
>
|
||||
CUSTOM
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</span>
|
||||
</li>
|
||||
</div>
|
||||
<li>
|
||||
<label for="url">{{ $t("url") }}</label>
|
||||
<input
|
||||
@@ -182,42 +184,32 @@
|
||||
id="url"
|
||||
name="url"
|
||||
type="url"
|
||||
v-model="uri"
|
||||
spellcheck="false"
|
||||
v-model="url"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<label for="path">{{ $t("path") }}</label>
|
||||
<input
|
||||
@keyup.enter="isValidURL ? sendRequest() : null"
|
||||
id="path"
|
||||
name="path"
|
||||
v-model="path"
|
||||
spellcheck="false"
|
||||
@input="pathInputHandler"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<label for="label">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="label"
|
||||
name="label"
|
||||
type="text"
|
||||
v-model="label"
|
||||
spellcheck="false"
|
||||
:placeholder="$t('optional')"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<label class="hide-on-small-screen" for="send"> </label>
|
||||
<button :disabled="!isValidURL" @click="sendRequest" id="send" ref="sendButton">
|
||||
{{ $t("send") }}
|
||||
<span>
|
||||
<i class="material-icons">send</i>
|
||||
</span>
|
||||
</button>
|
||||
</li>
|
||||
<div>
|
||||
<li>
|
||||
<label class="hide-on-small-screen" for="send"> </label>
|
||||
<button :disabled="!isValidURL" @click="sendRequest" id="send" ref="sendButton">
|
||||
{{ $t("send") }}
|
||||
<span>
|
||||
<i class="material-icons">send</i>
|
||||
</span>
|
||||
</button>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
<div class="blue">
|
||||
<label for="label">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="label"
|
||||
name="label"
|
||||
type="text"
|
||||
v-model="label"
|
||||
:placeholder="$t('optional')"
|
||||
/>
|
||||
</div>
|
||||
<div class="blue" label="Request Body" v-if="['POST', 'PUT', 'PATCH'].includes(method)">
|
||||
<ul>
|
||||
<li>
|
||||
@@ -1315,7 +1307,6 @@ import { tokenRequest, oauthRedirect } from "../assets/js/oauth"
|
||||
import { sendNetworkRequest } from "../functions/network"
|
||||
import { fb } from "../functions/fb"
|
||||
import { getEditorLangForMimeType } from "~/functions/editorutils"
|
||||
|
||||
const statusCategories = [
|
||||
{
|
||||
name: "informational",
|
||||
@@ -1365,12 +1356,10 @@ const parseHeaders = xhr => {
|
||||
}
|
||||
export const findStatusGroup = responseStatus =>
|
||||
statusCategories.find(status => status.statusCodeRegex.test(responseStatus))
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
textareaAutoHeight,
|
||||
},
|
||||
|
||||
components: {
|
||||
"pw-section": section,
|
||||
"pw-toggle": () => import("../components/toggle"),
|
||||
@@ -1407,13 +1396,11 @@ export default {
|
||||
showTokenList: false,
|
||||
showTokenRequest: false,
|
||||
showTokenRequestList: false,
|
||||
|
||||
/**
|
||||
* These are content types that can be automatically
|
||||
* serialized by postwoman.
|
||||
*/
|
||||
knownContentTypes: ["application/json", "application/x-www-form-urlencoded"],
|
||||
|
||||
/**
|
||||
* These are a list of Content Types known to Postwoman.
|
||||
*/
|
||||
@@ -1425,9 +1412,7 @@ export default {
|
||||
"text/html",
|
||||
"text/plain",
|
||||
],
|
||||
|
||||
commonHeaders,
|
||||
|
||||
showRequestModal: false,
|
||||
editRequest: {},
|
||||
urlExcludes: {},
|
||||
@@ -1509,7 +1494,6 @@ export default {
|
||||
} else {
|
||||
path = path + queryString
|
||||
}
|
||||
|
||||
this.path = path
|
||||
},
|
||||
deep: true,
|
||||
@@ -1517,6 +1501,7 @@ export default {
|
||||
selectedRequest(newValue, oldValue) {
|
||||
// @TODO: Convert all variables to single request variable
|
||||
if (!newValue) return
|
||||
this.uri = newValue.url + newValue.path
|
||||
this.url = newValue.url
|
||||
this.path = newValue.path
|
||||
this.method = newValue.method
|
||||
@@ -1543,6 +1528,33 @@ export default {
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
uri: {
|
||||
get() {
|
||||
return this.$store.state.request.uri ?
|
||||
this.$store.state.request.uri
|
||||
: this.url + this.path;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("setState", { value, attribute: "uri" })
|
||||
let url;
|
||||
if (this.preRequestScript && this.showPreRequestScript) {
|
||||
const environmentVariables = getEnvironmentVariablesFromScript(this.preRequestScript);
|
||||
url = parseTemplateString(value, environmentVariables);
|
||||
}
|
||||
try {
|
||||
url = new URL(url);
|
||||
this.url = url.origin;
|
||||
this.path = url.pathname;
|
||||
} catch(error) {
|
||||
console.log(error)
|
||||
let uriRegex = value.match(
|
||||
/^((http[s]?:\/\/)?(<<[^\/]+>>)?[^\/]*|)(\/?.*)$/
|
||||
);
|
||||
this.url = uriRegex[1];
|
||||
this.path = uriRegex[4];
|
||||
}
|
||||
}
|
||||
},
|
||||
url: {
|
||||
get() {
|
||||
return this.$store.state.request.url
|
||||
@@ -1771,7 +1783,6 @@ export default {
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
selectedRequest() {
|
||||
return this.$store.state.postwoman.selectedRequest
|
||||
},
|
||||
@@ -1972,6 +1983,7 @@ export default {
|
||||
handleUseHistory({ label, method, url, path, usesScripts, preRequestScript }) {
|
||||
this.label = label
|
||||
this.method = method
|
||||
this.uri = url + path
|
||||
this.url = url
|
||||
this.path = path
|
||||
this.showPreRequestScript = usesScripts
|
||||
@@ -2007,31 +2019,26 @@ export default {
|
||||
if (typeof requestOptions.data === "string") {
|
||||
requestOptions.data = parseTemplateString(requestOptions.data)
|
||||
}
|
||||
|
||||
return await sendNetworkRequest(requestOptions, this.$store)
|
||||
},
|
||||
async sendRequest() {
|
||||
this.$toast.clear()
|
||||
if (this.settings.SCROLL_INTO_ENABLED) this.scrollInto("response")
|
||||
|
||||
if (!this.isValidURL) {
|
||||
this.$toast.error(this.$t("url_invalid_format"), {
|
||||
icon: "error",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Start showing the loading bar as soon as possible.
|
||||
// The nuxt axios module will hide it when the request is made.
|
||||
this.$nuxt.$loading.start()
|
||||
|
||||
if (this.$refs.response.$el.classList.contains("hidden")) {
|
||||
this.$refs.response.$el.classList.toggle("hidden")
|
||||
}
|
||||
this.previewEnabled = false
|
||||
this.response.status = this.$t("fetching")
|
||||
this.response.body = this.$t("loading")
|
||||
|
||||
const auth =
|
||||
this.auth === "Basic Auth"
|
||||
? {
|
||||
@@ -2039,29 +2046,23 @@ export default {
|
||||
password: this.httpPassword,
|
||||
}
|
||||
: null
|
||||
|
||||
let headers = {}
|
||||
let headersObject = {}
|
||||
|
||||
Object.keys(headers).forEach(id => {
|
||||
headersObject[headers[id].key] = headers[id].value
|
||||
})
|
||||
headers = headersObject
|
||||
|
||||
// If the request has a body, we want to ensure Content-Length and
|
||||
// Content-Type are sent.
|
||||
let requestBody
|
||||
if (this.hasRequestBody) {
|
||||
requestBody = this.rawInput ? this.rawParams : this.rawRequestBody
|
||||
|
||||
Object.assign(headers, {
|
||||
//'Content-Length': requestBody.length,
|
||||
"Content-Type": `${this.contentType}; charset=utf-8`,
|
||||
})
|
||||
}
|
||||
|
||||
requestBody = requestBody ? requestBody.toString() : null
|
||||
|
||||
if (this.files.length !== 0) {
|
||||
const formData = new FormData()
|
||||
for (let i = 0; i < this.files.length; i++) {
|
||||
@@ -2071,37 +2072,30 @@ export default {
|
||||
formData.append("data", requestBody)
|
||||
requestBody = formData
|
||||
}
|
||||
|
||||
// If the request uses a token for auth, we want to make sure it's sent here.
|
||||
if (this.auth === "Bearer Token" || this.auth === "OAuth 2.0")
|
||||
headers["Authorization"] = `Bearer ${this.bearerToken}`
|
||||
|
||||
headers = Object.assign(
|
||||
// Clone the app headers object first, we don't want to
|
||||
// mutate it with the request headers added by default.
|
||||
Object.assign({}, this.headers)
|
||||
|
||||
// We make our temporary headers object the source so
|
||||
// that you can override the added headers if you
|
||||
// specify them.
|
||||
// headers
|
||||
)
|
||||
|
||||
Object.keys(headers).forEach(id => {
|
||||
headersObject[headers[id].key] = headers[id].value
|
||||
})
|
||||
headers = headersObject
|
||||
|
||||
try {
|
||||
const startTime = Date.now()
|
||||
|
||||
const payload = await this.makeRequest(
|
||||
auth,
|
||||
headers,
|
||||
requestBody,
|
||||
this.showPreRequestScript && this.preRequestScript
|
||||
)
|
||||
|
||||
const duration = Date.now() - startTime
|
||||
this.$toast.info(this.$t("finished_in", { duration }), {
|
||||
icon: "done",
|
||||
@@ -2109,13 +2103,10 @@ export default {
|
||||
;(() => {
|
||||
const status = (this.response.status = payload.status)
|
||||
const headers = (this.response.headers = payload.headers)
|
||||
|
||||
// We don't need to bother parsing JSON, axios already handles it for us!
|
||||
const body = (this.response.body = payload.data)
|
||||
|
||||
const date = new Date().toLocaleDateString()
|
||||
const time = new Date().toLocaleTimeString()
|
||||
|
||||
// Addition of an entry to the history component.
|
||||
const entry = {
|
||||
label: this.requestName,
|
||||
@@ -2137,7 +2128,6 @@ export default {
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
// tests
|
||||
const syntheticResponse = {
|
||||
status: this.response.status,
|
||||
@@ -2154,7 +2144,6 @@ export default {
|
||||
this.response.headers = error.response.headers
|
||||
this.response.status = error.response.status
|
||||
this.response.body = error.response.data
|
||||
|
||||
// Addition of an entry to the history component.
|
||||
const entry = {
|
||||
label: this.requestName,
|
||||
@@ -2223,7 +2212,6 @@ export default {
|
||||
removeRequestHeader(index) {
|
||||
// .slice() gives us an entirely new array rather than giving us just the reference
|
||||
const oldHeaders = this.headers.slice()
|
||||
|
||||
this.$store.commit("removeHeaders", index)
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
@@ -2243,7 +2231,6 @@ export default {
|
||||
removeRequestParam(index) {
|
||||
// .slice() gives us an entirely new array rather than giving us just the reference
|
||||
const oldParams = this.params.slice()
|
||||
|
||||
this.$store.commit("removeParams", index)
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
@@ -2263,7 +2250,6 @@ export default {
|
||||
removeRequestBodyParam(index) {
|
||||
// .slice() gives us an entirely new array rather than giving us just the reference
|
||||
const oldBodyParams = this.bodyParams.slice()
|
||||
|
||||
this.$store.commit("removeBodyParams", index)
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
@@ -2396,7 +2382,6 @@ export default {
|
||||
.map(item => flat(item))
|
||||
const deeps = ["headers", "params"].map(item => deep(item))
|
||||
const bodyParams = this.rawInput ? [flat("rawParams")] : [deep("bodyParams")]
|
||||
|
||||
history.replaceState(
|
||||
window.location.href,
|
||||
"",
|
||||
@@ -2543,7 +2528,6 @@ export default {
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.editRequest = {
|
||||
url: this.url,
|
||||
path: this.path,
|
||||
@@ -2561,11 +2545,9 @@ export default {
|
||||
contentType: this.contentType,
|
||||
requestType: this.requestType,
|
||||
}
|
||||
|
||||
if (this.selectedRequest.url) {
|
||||
this.editRequest = Object.assign({}, this.selectedRequest, this.editRequest)
|
||||
}
|
||||
|
||||
this.showRequestModal = true
|
||||
},
|
||||
hideRequestModal() {
|
||||
@@ -2750,7 +2732,6 @@ export default {
|
||||
httpPassword: true,
|
||||
bearerToken: true,
|
||||
}
|
||||
|
||||
if (Object.keys(this.$route.query).length) this.setRouteQueries(this.$route.query)
|
||||
this.$watch(
|
||||
vm => [
|
||||
|
||||
2937
pages/index.vue.orig
Normal file
2937
pages/index.vue.orig
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
export default () => ({
|
||||
request: {
|
||||
method: "GET",
|
||||
uri: "",
|
||||
url: "https://httpbin.org",
|
||||
path: "/get",
|
||||
label: "",
|
||||
|
||||
@@ -3,8 +3,6 @@ describe("Proxy disabled - local request", () => {
|
||||
cy.seedAndVisit("catapi", "/?url=https://api.thecatapi.com&path=")
|
||||
.get("#url")
|
||||
.then(el => expect(el.val() === "https://api.thecatapi.com").to.equal(true))
|
||||
.get("#path")
|
||||
.then(el => expect(el.val() === "").to.equal(true))
|
||||
.get("#response-details-wrapper")
|
||||
.should($wrapper => {
|
||||
expect($wrapper).to.contain("FAKE Cat API")
|
||||
|
||||
Reference in New Issue
Block a user