Files
hoppscotch/packages/hoppscotch-app/src/newstore/RESTSession.ts
Andrew Bastin 8b300fab5d feat: migrate to vue 3 + vite (#2553)
Co-authored-by: amk-dev <akash.k.mohan98@gmail.com>
Co-authored-by: liyasthomas <liyascthomas@gmail.com>
2022-09-29 10:55:21 +05:30

711 lines
16 KiB
TypeScript

import { pluck, distinctUntilChanged, map, filter } from "rxjs/operators"
import { Ref } from "vue"
import {
FormDataKeyValue,
HoppRESTHeader,
HoppRESTParam,
HoppRESTReqBody,
HoppRESTRequest,
RESTReqSchemaVersion,
HoppRESTAuth,
ValidContentTypes,
} from "@hoppscotch/data"
import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
import { useStream } from "@composables/stream"
import { HoppTestResult } from "~/helpers/types/HoppTestResult"
import { HoppRequestSaveContext } from "~/helpers/types/HoppRequestSaveContext"
import { applyBodyTransition } from "~/helpers/rules/BodyTransition"
type RESTSession = {
request: HoppRESTRequest
response: HoppRESTResponse | null
testResults: HoppTestResult | null
saveContext: HoppRequestSaveContext | null
}
export const getDefaultRESTRequest = (): HoppRESTRequest => ({
v: RESTReqSchemaVersion,
endpoint: "https://echo.hoppscotch.io",
name: "Untitled request",
params: [],
headers: [],
method: "GET",
auth: {
authType: "none",
authActive: true,
},
preRequestScript: "",
testScript: "",
body: {
contentType: null,
body: null,
},
})
const defaultRESTSession: RESTSession = {
request: getDefaultRESTRequest(),
response: null,
testResults: null,
saveContext: null,
}
const dispatchers = defineDispatchers({
setRequest(_: RESTSession, { req }: { req: HoppRESTRequest }) {
return {
request: req,
}
},
setRequestName(curr: RESTSession, { newName }: { newName: string }) {
return {
request: {
...curr.request,
name: newName,
},
}
},
setEndpoint(curr: RESTSession, { newEndpoint }: { newEndpoint: string }) {
return {
request: {
...curr.request,
endpoint: newEndpoint,
},
}
},
setParams(curr: RESTSession, { entries }: { entries: HoppRESTParam[] }) {
return {
request: {
...curr.request,
params: entries,
},
}
},
addParam(curr: RESTSession, { newParam }: { newParam: HoppRESTParam }) {
return {
request: {
...curr.request,
params: [...curr.request.params, newParam],
},
}
},
updateParam(
curr: RESTSession,
{ index, updatedParam }: { index: number; updatedParam: HoppRESTParam }
) {
const newParams = curr.request.params.map((param, i) => {
if (i === index) return updatedParam
else return param
})
return {
request: {
...curr.request,
params: newParams,
},
}
},
deleteParam(curr: RESTSession, { index }: { index: number }) {
const newParams = curr.request.params.filter((_x, i) => i !== index)
return {
request: {
...curr.request,
params: newParams,
},
}
},
deleteAllParams(curr: RESTSession) {
return {
request: {
...curr.request,
params: [],
},
}
},
updateMethod(curr: RESTSession, { newMethod }: { newMethod: string }) {
return {
request: {
...curr.request,
method: newMethod,
},
}
},
setHeaders(curr: RESTSession, { entries }: { entries: HoppRESTHeader[] }) {
return {
request: {
...curr.request,
headers: entries,
},
}
},
addHeader(curr: RESTSession, { entry }: { entry: HoppRESTHeader }) {
return {
request: {
...curr.request,
headers: [...curr.request.headers, entry],
},
}
},
updateHeader(
curr: RESTSession,
{ index, updatedEntry }: { index: number; updatedEntry: HoppRESTHeader }
) {
return {
request: {
...curr.request,
headers: curr.request.headers.map((header, i) => {
if (i === index) return updatedEntry
else return header
}),
},
}
},
deleteHeader(curr: RESTSession, { index }: { index: number }) {
return {
request: {
...curr.request,
headers: curr.request.headers.filter((_, i) => i !== index),
},
}
},
deleteAllHeaders(curr: RESTSession) {
return {
request: {
...curr.request,
headers: [],
},
}
},
setAuth(curr: RESTSession, { newAuth }: { newAuth: HoppRESTAuth }) {
return {
request: {
...curr.request,
auth: newAuth,
},
}
},
setPreRequestScript(curr: RESTSession, { newScript }: { newScript: string }) {
return {
request: {
...curr.request,
preRequestScript: newScript,
},
}
},
setTestScript(curr: RESTSession, { newScript }: { newScript: string }) {
return {
request: {
...curr.request,
testScript: newScript,
},
}
},
setContentType(
curr: RESTSession,
{ newContentType }: { newContentType: ValidContentTypes | null }
) {
// TODO: persist body evenafter switching content typees
return {
request: {
...curr.request,
body: applyBodyTransition(curr.request.body, newContentType),
},
}
},
addFormDataEntry(curr: RESTSession, { entry }: { entry: FormDataKeyValue }) {
// Only perform update if the current content-type is formdata
if (curr.request.body.contentType !== "multipart/form-data") return {}
return {
request: {
...curr.request,
body: <HoppRESTReqBody>{
contentType: "multipart/form-data",
body: [...curr.request.body.body, entry],
},
},
}
},
deleteFormDataEntry(curr: RESTSession, { index }: { index: number }) {
// Only perform update if the current content-type is formdata
if (curr.request.body.contentType !== "multipart/form-data") return {}
return {
request: {
...curr.request,
body: <HoppRESTReqBody>{
contentType: "multipart/form-data",
body: curr.request.body.body.filter((_, i) => i !== index),
},
},
}
},
updateFormDataEntry(
curr: RESTSession,
{ index, entry }: { index: number; entry: FormDataKeyValue }
) {
// Only perform update if the current content-type is formdata
if (curr.request.body.contentType !== "multipart/form-data") return {}
return {
request: {
...curr.request,
body: <HoppRESTReqBody>{
contentType: "multipart/form-data",
body: curr.request.body.body.map((x, i) => (i !== index ? x : entry)),
},
},
}
},
deleteAllFormDataEntries(curr: RESTSession) {
// Only perform update if the current content-type is formdata
if (curr.request.body.contentType !== "multipart/form-data") return {}
return {
request: {
...curr.request,
body: <HoppRESTReqBody>{
contentType: "multipart/form-data",
body: [],
},
},
}
},
setRequestBody(curr: RESTSession, { newBody }: { newBody: HoppRESTReqBody }) {
return {
request: {
...curr.request,
body: newBody,
},
}
},
updateResponse(
_curr: RESTSession,
{ updatedRes }: { updatedRes: HoppRESTResponse | null }
) {
return {
response: updatedRes,
}
},
// eslint-disable-next-line @typescript-eslint/no-unused-vars
clearResponse(_curr: RESTSession) {
return {
response: null,
}
},
setTestResults(
_curr: RESTSession,
{ newResults }: { newResults: HoppTestResult | null }
) {
return {
testResults: newResults,
}
},
setSaveContext(
_,
{ newContext }: { newContext: HoppRequestSaveContext | null }
) {
return {
saveContext: newContext,
}
},
})
const restSessionStore = new DispatchingStore(defaultRESTSession, dispatchers)
export function getRESTRequest() {
return restSessionStore.subject$.value.request
}
export function setRESTRequest(
req: HoppRESTRequest,
saveContext?: HoppRequestSaveContext | null
) {
restSessionStore.dispatch({
dispatcher: "setRequest",
payload: {
req,
},
})
if (saveContext) setRESTSaveContext(saveContext)
}
export function setRESTSaveContext(saveContext: HoppRequestSaveContext | null) {
restSessionStore.dispatch({
dispatcher: "setSaveContext",
payload: {
newContext: saveContext,
},
})
}
export function getRESTSaveContext() {
return restSessionStore.value.saveContext
}
export function resetRESTRequest() {
setRESTRequest(getDefaultRESTRequest())
}
export function setRESTEndpoint(newEndpoint: string) {
restSessionStore.dispatch({
dispatcher: "setEndpoint",
payload: {
newEndpoint,
},
})
}
export function setRESTRequestName(newName: string) {
restSessionStore.dispatch({
dispatcher: "setRequestName",
payload: {
newName,
},
})
}
export function setRESTParams(entries: HoppRESTParam[]) {
restSessionStore.dispatch({
dispatcher: "setParams",
payload: {
entries,
},
})
}
export function addRESTParam(newParam: HoppRESTParam) {
restSessionStore.dispatch({
dispatcher: "addParam",
payload: {
newParam,
},
})
}
export function updateRESTParam(index: number, updatedParam: HoppRESTParam) {
restSessionStore.dispatch({
dispatcher: "updateParam",
payload: {
updatedParam,
index,
},
})
}
export function deleteRESTParam(index: number) {
restSessionStore.dispatch({
dispatcher: "deleteParam",
payload: {
index,
},
})
}
export function deleteAllRESTParams() {
restSessionStore.dispatch({
dispatcher: "deleteAllParams",
payload: {},
})
}
export function updateRESTMethod(newMethod: string) {
restSessionStore.dispatch({
dispatcher: "updateMethod",
payload: {
newMethod,
},
})
}
export function setRESTHeaders(entries: HoppRESTHeader[]) {
restSessionStore.dispatch({
dispatcher: "setHeaders",
payload: {
entries,
},
})
}
export function addRESTHeader(entry: HoppRESTHeader) {
restSessionStore.dispatch({
dispatcher: "addHeader",
payload: {
entry,
},
})
}
export function updateRESTHeader(index: number, updatedEntry: HoppRESTHeader) {
restSessionStore.dispatch({
dispatcher: "updateHeader",
payload: {
index,
updatedEntry,
},
})
}
export function deleteRESTHeader(index: number) {
restSessionStore.dispatch({
dispatcher: "deleteHeader",
payload: {
index,
},
})
}
export function deleteAllRESTHeaders() {
restSessionStore.dispatch({
dispatcher: "deleteAllHeaders",
payload: {},
})
}
export function setRESTAuth(newAuth: HoppRESTAuth) {
restSessionStore.dispatch({
dispatcher: "setAuth",
payload: {
newAuth,
},
})
}
export function setRESTPreRequestScript(newScript: string) {
restSessionStore.dispatch({
dispatcher: "setPreRequestScript",
payload: {
newScript,
},
})
}
export function setRESTTestScript(newScript: string) {
restSessionStore.dispatch({
dispatcher: "setTestScript",
payload: {
newScript,
},
})
}
export function setRESTReqBody(newBody: HoppRESTReqBody | null) {
restSessionStore.dispatch({
dispatcher: "setRequestBody",
payload: {
newBody,
},
})
}
export function updateRESTResponse(updatedRes: HoppRESTResponse | null) {
restSessionStore.dispatch({
dispatcher: "updateResponse",
payload: {
updatedRes,
},
})
}
export function clearRESTResponse() {
restSessionStore.dispatch({
dispatcher: "clearResponse",
payload: {},
})
}
export function setRESTTestResults(newResults: HoppTestResult | null) {
restSessionStore.dispatch({
dispatcher: "setTestResults",
payload: {
newResults,
},
})
}
export function addFormDataEntry(entry: FormDataKeyValue) {
restSessionStore.dispatch({
dispatcher: "addFormDataEntry",
payload: {
entry,
},
})
}
export function deleteFormDataEntry(index: number) {
restSessionStore.dispatch({
dispatcher: "deleteFormDataEntry",
payload: {
index,
},
})
}
export function updateFormDataEntry(index: number, entry: FormDataKeyValue) {
restSessionStore.dispatch({
dispatcher: "updateFormDataEntry",
payload: {
index,
entry,
},
})
}
export function setRESTContentType(newContentType: ValidContentTypes | null) {
restSessionStore.dispatch({
dispatcher: "setContentType",
payload: {
newContentType,
},
})
}
export function deleteAllFormDataEntries() {
restSessionStore.dispatch({
dispatcher: "deleteAllFormDataEntries",
payload: {},
})
}
export const restSaveContext$ = restSessionStore.subject$.pipe(
pluck("saveContext"),
distinctUntilChanged()
)
export const restRequest$ = restSessionStore.subject$.pipe(
pluck("request"),
distinctUntilChanged()
)
export const restRequestName$ = restRequest$.pipe(
pluck("name"),
distinctUntilChanged()
)
export const restEndpoint$ = restSessionStore.subject$.pipe(
pluck("request", "endpoint"),
distinctUntilChanged()
)
export const restParams$ = restSessionStore.subject$.pipe(
pluck("request", "params"),
distinctUntilChanged()
)
export const restActiveParamsCount$ = restParams$.pipe(
map(
(params) =>
params.filter((x) => x.active && (x.key !== "" || x.value !== "")).length
)
)
export const restMethod$ = restSessionStore.subject$.pipe(
pluck("request", "method"),
distinctUntilChanged()
)
export const restHeaders$ = restSessionStore.subject$.pipe(
pluck("request", "headers"),
distinctUntilChanged()
)
export const restActiveHeadersCount$ = restHeaders$.pipe(
map(
(params) =>
params.filter((x) => x.active && (x.key !== "" || x.value !== "")).length
)
)
export const restAuth$ = restRequest$.pipe(pluck("auth"))
export const restPreRequestScript$ = restSessionStore.subject$.pipe(
pluck("request", "preRequestScript"),
distinctUntilChanged()
)
export const restContentType$ = restRequest$.pipe(
pluck("body", "contentType"),
distinctUntilChanged()
)
export const restTestScript$ = restSessionStore.subject$.pipe(
pluck("request", "testScript"),
distinctUntilChanged()
)
export const restReqBody$ = restSessionStore.subject$.pipe(
pluck("request", "body"),
distinctUntilChanged()
)
export const restResponse$ = restSessionStore.subject$.pipe(
pluck("response"),
distinctUntilChanged()
)
export const completedRESTResponse$ = restResponse$.pipe(
filter(
(res) =>
res !== null &&
res.type !== "loading" &&
res.type !== "network_fail" &&
res.type !== "script_fail"
)
)
export const restTestResults$ = restSessionStore.subject$.pipe(
pluck("testResults"),
distinctUntilChanged()
)
/**
* A Vue 3 composable function that gives access to a ref
* which is updated to the preRequestScript value in the store.
* The ref value is kept in sync with the store and all writes
* to the ref are dispatched to the store as `setPreRequestScript`
* dispatches.
*/
export function usePreRequestScript(): Ref<string> {
return useStream(
restPreRequestScript$,
restSessionStore.value.request.preRequestScript,
(value) => {
setRESTPreRequestScript(value)
}
)
}
/**
* A Vue 3 composable function that gives access to a ref
* which is updated to the testScript value in the store.
* The ref value is kept in sync with the store and all writes
* to the ref are dispatched to the store as `setTestScript`
* dispatches.
*/
export function useTestScript(): Ref<string> {
return useStream(
restTestScript$,
restSessionStore.value.request.testScript,
(value) => {
setRESTTestScript(value)
}
)
}
export function useRESTRequestBody(): Ref<HoppRESTReqBody> {
return useStream(
restReqBody$,
restSessionStore.value.request.body,
setRESTReqBody
)
}
export function useRESTRequestName(): Ref<string> {
return useStream(
restRequestName$,
restSessionStore.value.request.name,
setRESTRequestName
)
}