Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"dev": "vite",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"test": "node --test",
"preview": "vite preview",
"dev:remote": "cross-env VITE_DEV_REMOTE=remote npm run dev"
},
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/request/buildQueryString.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export function buildQueryString(options = {}) {
const searchParams = new URLSearchParams();

Object.entries(options).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
searchParams.set(key, value);
}
});

const queryString = searchParams.toString();

return queryString ? `?${queryString}` : '';
}
37 changes: 37 additions & 0 deletions frontend/src/request/buildQueryString.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import assert from 'node:assert/strict';
import test from 'node:test';

import { buildQueryString } from './buildQueryString.js';

test('returns an empty string when no options are provided', () => {
assert.equal(buildQueryString(), '');
});

test('encodes reserved characters and preserves their values', () => {
const queryString = buildQueryString({
q: 'ACME & Sons + Partners #1',
fields: 'name,email',
});
const searchParams = new URLSearchParams(queryString);

assert.equal(searchParams.get('q'), 'ACME & Sons + Partners #1');
assert.equal(searchParams.get('fields'), 'name,email');
assert.match(queryString, /%26/);
assert.match(queryString, /%2B/);
assert.match(queryString, /%23/);
});

test('preserves falsy values and omits missing values', () => {
const queryString = buildQueryString({
page: 0,
enabled: false,
filter: undefined,
equal: null,
});
const searchParams = new URLSearchParams(queryString);

assert.equal(searchParams.get('page'), '0');
assert.equal(searchParams.get('enabled'), 'false');
assert.equal(searchParams.has('filter'), false);
assert.equal(searchParams.has('equal'), false);
});
29 changes: 6 additions & 23 deletions frontend/src/request/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { API_BASE_URL } from '@/config/serverApiConfig';
import errorHandler from './errorHandler';
import successHandler from './successHandler';
import storePersist from '@/redux/storePersist';
import { buildQueryString } from './buildQueryString';

function findKeyByPrefix(object, prefix) {
for (var property in object) {
Expand Down Expand Up @@ -116,9 +117,7 @@ const request = {
filter: async ({ entity, options = {} }) => {
try {
includeToken();
let filter = options.filter ? 'filter=' + options.filter : '';
let equal = options.equal ? '&equal=' + options.equal : '';
let query = `?${filter}${equal}`;
const query = buildQueryString(options);

const response = await axios.get(entity + '/filter' + query);
successHandler(response, {
Expand All @@ -134,11 +133,7 @@ const request = {
search: async ({ entity, options = {} }) => {
try {
includeToken();
let query = '?';
for (var key in options) {
query += key + '=' + options[key] + '&';
}
query = query.slice(0, -1);
const query = buildQueryString(options);
// headersInstance.cancelToken = source.token;
const response = await axios.get(entity + '/search' + query);

Expand All @@ -155,11 +150,7 @@ const request = {
list: async ({ entity, options = {} }) => {
try {
includeToken();
let query = '?';
for (var key in options) {
query += key + '=' + options[key] + '&';
}
query = query.slice(0, -1);
const query = buildQueryString(options);

const response = await axios.get(entity + '/list' + query);

Expand All @@ -175,11 +166,7 @@ const request = {
listAll: async ({ entity, options = {} }) => {
try {
includeToken();
let query = '?';
for (var key in options) {
query += key + '=' + options[key] + '&';
}
query = query.slice(0, -1);
const query = buildQueryString(options);

const response = await axios.get(entity + '/listAll' + query);

Expand Down Expand Up @@ -253,11 +240,7 @@ const request = {
summary: async ({ entity, options = {} }) => {
try {
includeToken();
let query = '?';
for (var key in options) {
query += key + '=' + options[key] + '&';
}
query = query.slice(0, -1);
const query = buildQueryString(options);
const response = await axios.get(entity + '/summary' + query);

successHandler(response, {
Expand Down
Loading