Skip to content

Commit

Permalink
fix/path param (#2388)
Browse files Browse the repository at this point in the history
* fix(#484): minor code fixes

* code fixes

* fixes for generateCode

* var change

* pr review fixes
  • Loading branch information
lohxt1 committed May 30, 2024
1 parent abfd14a commit 470d162
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 90 deletions.
36 changes: 18 additions & 18 deletions packages/bruno-app/src/components/RequestPane/QueryParams/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,10 @@ const QueryParams = ({ item, collection }) => {
const onSave = () => dispatch(saveRequest(item.uid, collection.uid));
const handleRun = () => dispatch(sendRequest(item, collection.uid));

const handleValueChange = (data, type, value) => {
const _data = cloneDeep(data);

if (!has(_data, type)) {
return;
}

_data[type] = value;

return _data;
};

const handleQueryParamChange = (e, data, type) => {
const handleQueryParamChange = (e, data, key) => {
let value;

switch (type) {
switch (key) {
case 'name': {
value = e.target.value;
break;
Expand All @@ -65,11 +53,17 @@ const QueryParams = ({ item, collection }) => {
}
}

const param = handleValueChange(data, type, value);
let queryParam = cloneDeep(data);

if (queryParam[key] === value) {
return;
}

queryParam[key] = value;

dispatch(
updateQueryParam({
param,
queryParam,
itemUid: item.uid,
collectionUid: collection.uid
})
Expand All @@ -79,11 +73,17 @@ const QueryParams = ({ item, collection }) => {
const handlePathParamChange = (e, data) => {
let value = e.target.value;

const path = handleValueChange(data, 'value', value);
let pathParam = cloneDeep(data);

if (pathParam['value'] === value) {
return;
}

pathParam['value'] = value;

dispatch(
updatePathParam({
path,
pathParam,
itemUid: item.uid,
collectionUid: collection.uid
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,42 +27,32 @@ const interpolateUrl = ({ url, envVars, collectionVariables, processEnvVars }) =
});
};

const joinPathUrl = (url, params) => {
const processPaths = (uri, paths) => {
return uri
// interpolate URL paths
const interpolateUrlPathParams = (url, params) => {
const getInterpolatedBasePath = (pathname, params) => {
return pathname
.split('/')
.map((segment) => {
if (segment.startsWith(':')) {
const paramName = segment.slice(1);
const param = paths.find((p) => p.name === paramName && p.type === 'path' && p.enabled);
return param ? param.value : segment;
const pathParamName = segment.slice(1);
const pathParam = params.find((p) => p?.name === pathParamName && p?.type === 'path');
return pathParam ? pathParam.value : segment;
}
return segment;
})
.join('/');
};

const processQueryParams = (search, params) => {
const queryParams = new URLSearchParams(search);
params
.filter((p) => p.type === 'query' && p.enabled)
.forEach((param) => {
queryParams.set(param.name, param.value);
});
return queryParams.toString();
};

let uri;
try {
uri = new URL(url);
} catch (error) {
uri = new URL(`http://${url}`);
}

const basePath = processPaths(uri.pathname, params);
const queryString = processQueryParams(uri.search, params);
const basePath = getInterpolatedBasePath(uri.pathname, params);

return `${uri.origin}${basePath}${queryString ? `?${queryString}` : ''}`;
return `${uri.origin}${basePath}${uri?.search || ''}`;
};

const languages = [
Expand Down Expand Up @@ -114,10 +104,6 @@ const languages = [
];

const GenerateCodeItem = ({ collection, item, onClose }) => {
const url = joinPathUrl(
get(item, 'draft.request.url') !== undefined ? get(item, 'draft.request.url') : get(item, 'request.url'),
get(item, 'draft.request.params') !== undefined ? get(item, 'draft.request.params') : get(item, 'request.params')
);
const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
let envVars = {};
if (environment) {
Expand All @@ -128,12 +114,23 @@ const GenerateCodeItem = ({ collection, item, onClose }) => {
}, {});
}

const requestUrl =
get(item, 'draft.request.url') !== undefined ? get(item, 'draft.request.url') : get(item, 'request.url');

// interpolate the query params
const interpolatedUrl = interpolateUrl({
url,
url: requestUrl,
envVars,
collectionVariables: collection.collectionVariables,
processEnvVars: collection.processEnvVariables
});

// interpolate the path params
const finalUrl = interpolateUrlPathParams(
interpolatedUrl,
get(item, 'draft.request.params') !== undefined ? get(item, 'draft.request.params') : get(item, 'request.params')
);

const [selectedLanguage, setSelectedLanguage] = useState(languages[0]);
return (
<Modal size="lg" title="Generate Code" handleCancel={onClose} hideFooter={true}>
Expand All @@ -157,7 +154,7 @@ const GenerateCodeItem = ({ collection, item, onClose }) => {
</div>
</div>
<div className="flex-grow p-4">
{isValidUrl(interpolatedUrl) ? (
{isValidUrl(finalUrl) ? (
<CodeView
language={selectedLanguage}
item={{
Expand All @@ -166,18 +163,18 @@ const GenerateCodeItem = ({ collection, item, onClose }) => {
item.request.url !== ''
? {
...item.request,
url: interpolatedUrl
url: finalUrl
}
: {
...item.draft.request,
url: interpolatedUrl
url: finalUrl
}
}}
/>
) : (
<div className="flex flex-col justify-center items-center w-full">
<div className="text-center">
<h1 className="text-2xl font-bold">Invalid URL: {interpolatedUrl}</h1>
<h1 className="text-2xl font-bold">Invalid URL: {url}</h1>
<p className="text-gray-500">Please check the URL and try again</p>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,39 +367,42 @@ export const collectionsSlice = createSlice({
}
item.draft.request.url = action.payload.url;

const parts = splitOnFirst(item.draft.request.url, '?');
const urlParams = parseQueryParams(parts[1]);
let urlPaths = [];
const parts = splitOnFirst(item?.draft?.request?.url, '?');
const urlQueryParams = parseQueryParams(parts[1]);
let urlPathParams = [];

try {
urlPaths = parsePathParams(parts[0]);
urlPathParams = parsePathParams(parts[0]);
} catch (err) {
console.error(err);
toast.error(err.message);
}

const disabledParams = filter(item.draft.request.params, (p) => !p.enabled);
let enabledParams = filter(item.draft.request.params, (p) => p.enabled && p.type === 'query');
let oldPaths = filter(item.draft.request.params, (p) => p.enabled && p.type === 'path');
let newPaths = [];
const disabledQueryParams = filter(item?.draft?.request?.params, (p) => !p.enabled && p.type === 'query');
let enabledQueryParams = filter(item?.draft?.request?.params, (p) => p.enabled && p.type === 'query');
let oldPathParams = filter(item?.draft?.request?.params, (p) => p.enabled && p.type === 'path');
let newPathParams = [];

// try and connect as much as old params uid's as possible
each(urlParams, (urlParam) => {
const existingParam = find(enabledParams, (p) => p.name === urlParam.name || p.value === urlParam.value);
urlParam.uid = existingParam ? existingParam.uid : uuid();
urlParam.enabled = true;
urlParam.type = 'query';
each(urlQueryParams, (urlQueryParam) => {
const existingQueryParam = find(
enabledQueryParams,
(p) => p?.name === urlQueryParam?.name || p?.value === urlQueryParam?.value
);
urlQueryParam.uid = existingQueryParam?.uid || uuid();
urlQueryParam.enabled = true;
urlQueryParam.type = 'query';

// once found, remove it - trying our best here to accommodate duplicate query params
if (existingParam) {
enabledParams = filter(enabledParams, (p) => p.uid !== existingParam.uid);
if (existingQueryParam) {
enabledQueryParams = filter(enabledQueryParams, (p) => p?.uid !== existingQueryParam?.uid);
}
});

// filter the newest path param and compare with previous data that already inserted
newPaths = filter(urlPaths, (urlPath) => {
const existingPath = find(oldPaths, (p) => p.name === urlPath.name);
if (existingPath) {
newPathParams = filter(urlPathParams, (urlPath) => {
const existingPathParam = find(oldPathParams, (p) => p.name === urlPath.name);
if (existingPathParam) {
return false;
}
urlPath.uid = uuid();
Expand All @@ -409,14 +412,14 @@ export const collectionsSlice = createSlice({
});

// remove path param that not used or deleted when typing url
oldPaths = filter(oldPaths, (urlPath) => {
return find(urlPaths, (p) => p.name === urlPath.name);
oldPathParams = filter(oldPathParams, (urlPath) => {
return find(urlPathParams, (p) => p.name === urlPath.name);
});

// ultimately params get replaced with params in url + the disabled ones that existed prior
// the query params are the source of truth, the url in the queryurl input gets constructed using these params
// we however are also storing the full url (with params) in the url itself
item.draft.request.params = concat(urlParams, newPaths, disabledParams, oldPaths);
item.draft.request.params = concat(urlQueryParams, newPathParams, disabledQueryParams, oldPathParams);
}
}
},
Expand Down Expand Up @@ -491,12 +494,12 @@ export const collectionsSlice = createSlice({
}
const queryParam = find(
item.draft.request.params,
(h) => h.uid === action.payload.param.uid && h.type === 'query'
(h) => h.uid === action.payload.queryParam.uid && h.type === 'query'
);
if (queryParam) {
queryParam.name = action.payload.param.name;
queryParam.value = action.payload.param.value;
queryParam.enabled = action.payload.param.enabled;
queryParam.name = action.payload.queryParam.name;
queryParam.value = action.payload.queryParam.value;
queryParam.enabled = action.payload.queryParam.enabled;

// update request url
const parts = splitOnFirst(item.draft.request.url, '?');
Expand Down Expand Up @@ -558,11 +561,14 @@ export const collectionsSlice = createSlice({
item.draft = cloneDeep(item);
}

const param = find(item.draft.request.params, (p) => p.uid === action.payload.path.uid && p.type === 'path');
const param = find(
item.draft.request.params,
(p) => p.uid === action.payload.pathParam.uid && p.type === 'path'
);

if (param) {
param.name = action.payload.path.name;
param.value = action.payload.path.value;
param.name = action.payload.pathParam.name;
param.value = action.payload.pathParam.value;
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/bruno-cli/src/runner/interpolate-vars.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
throw { message: 'Invalid URL format', originalError: e.message };
}

const urlPaths = url.pathname
const interpolatedUrlPath = url.pathname
.split('/')
.filter((path) => path !== '')
.map((path) => {
Expand All @@ -113,7 +113,7 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
})
.join('');

request.url = url.origin + urlPaths + url.search;
request.url = url.origin + interpolatedUrlPath + url.search;
}

if (request.proxy) {
Expand Down
3 changes: 1 addition & 2 deletions packages/bruno-cli/src/runner/prepare-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ const prepareRequest = (request, collectionRoot) => {
let axiosRequest = {
method: request.method,
url: request.url,
headers: headers,
paths: request.paths
headers: headers
};

const collectionAuth = get(collectionRoot, 'request.auth');
Expand Down
4 changes: 2 additions & 2 deletions packages/bruno-electron/src/ipc/network/interpolate-vars.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
throw { message: 'Invalid URL format', originalError: e.message };
}

const urlPaths = url.pathname
const urlPathnameInterpolatedWithPathParams = url.pathname
.split('/')
.filter((path) => path !== '')
.map((path) => {
Expand All @@ -113,7 +113,7 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
})
.join('');

request.url = url.origin + urlPaths + url.search;
request.url = url.origin + urlPathnameInterpolatedWithPathParams + url.search;
}

if (request.proxy) {
Expand Down
8 changes: 4 additions & 4 deletions packages/bruno-lang/v2/src/bruToJson.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ const mapPairListToKeyValPairs = (pairList = [], parseEnabled = true) => {
});
};

const mapPairListToKeyValPairsWithType = (pairList = [], type) => {
const mapRequestParams = (pairList = [], type) => {
if (!pairList.length) {
return [];
}
Expand Down Expand Up @@ -346,17 +346,17 @@ const sem = grammar.createSemantics().addAttribute('ast', {
},
query(_1, dictionary) {
return {
params: mapPairListToKeyValPairsWithType(dictionary.ast, 'query')
params: mapRequestParams(dictionary.ast, 'query')
};
},
paramspath(_1, dictionary) {
return {
params: mapPairListToKeyValPairsWithType(dictionary.ast, 'path')
params: mapRequestParams(dictionary.ast, 'path')
};
},
paramsquery(_1, dictionary) {
return {
params: mapPairListToKeyValPairsWithType(dictionary.ast, 'query')
params: mapRequestParams(dictionary.ast, 'query')
};
},
headers(_1, dictionary) {
Expand Down
4 changes: 2 additions & 2 deletions packages/bruno-schema/src/collections/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ const authSchema = Yup.object({
.noUnknown(true)
.strict();

const keyValueWithTypeSchema = Yup.object({
const requestParamsSchema = Yup.object({
uid: uidSchema,
name: Yup.string().nullable(),
value: Yup.string().nullable(),
Expand All @@ -203,7 +203,7 @@ const requestSchema = Yup.object({
url: requestUrlSchema,
method: requestMethodSchema,
headers: Yup.array().of(keyValueSchema).required('headers are required'),
params: Yup.array().of(keyValueWithTypeSchema).required('params are required'),
params: Yup.array().of(requestParamsSchema).required('params are required'),
auth: authSchema,
body: requestBodySchema,
script: Yup.object({
Expand Down

0 comments on commit 470d162

Please sign in to comment.