Skip to content

Commit b8f50cb

Browse files
committed
feat: add basePath option and optimize SRP
1 parent 185c727 commit b8f50cb

File tree

4 files changed

+82
-33
lines changed

4 files changed

+82
-33
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
### Added
11+
12+
- Option to define `basePath`.
13+
14+
### Fixed
15+
16+
- Default value for `option` parameters.
17+
- Optimizations for single responsibility principle (SRP).
18+
819
## [0.2.0] - 2023-04-17
920

1021
### Added

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ Creates a client.
126126
| Parameter | Required? | Type | Default | Description |
127127
|:-------------------------|:----------|:--------------------|:---------------------------|:----------------------------------------------------------------------|
128128
| `options` | No | `Object` | `{}` | The options for the client. |
129-
| `options.baseUrl` | No | `string` | `window.location.pathname` | The base URL for the API. |
129+
| `options.basePath` | No | `string` | `/api` | The base path of the API. |
130+
| `options.baseUrl` | No | `string` | `window.location.pathname` | The base URL of the API. |
130131
| `options.fetchClient` | No | `Function` | `fetch` | The fetch client to use. Tested with `fetch` and `axios`. |
131132
| `options.fetchOptions` | No | `Object` | `{}` | The fetch client options. |
132133
| `options.locale` | No | `string` | `''` | The locale for every request. |

src/client.js

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* An API client for SuluHeadlessBundle.
55
*/
66
export default class Client {
7+
basePath;
78
baseUrl;
89
fetchClient;
910
fetchOptions;
@@ -15,8 +16,9 @@ export default class Client {
1516
/**
1617
* Creates a client.
1718
*
18-
* @param {Object} options - The options for the client.
19-
* @param {string} [options.baseUrl=window.location.origin] - The base URL for the API.
19+
* @param {Object} [options={}] - The options for the client.
20+
* @param {string} [options.baseUrl='/api'] - The base path of the API.
21+
* @param {string} [options.baseUrl=window.location.origin] - The base URL of the API.
2022
* @param {function} [options.fetchClient=fetch.bind(window)] - The fetch client to use.
2123
* @param {Object} [options.fetchOptions={}] - The fetch client options.
2224
* @param {string} [options.locale=''] - The locale for every request.
@@ -25,14 +27,16 @@ export default class Client {
2527
* @param {boolean} [options.removeEmbedded=false] - Whether to remove the _embedded layer from the response if present.
2628
*/
2729
constructor({
30+
basePath = '/api',
2831
baseUrl = window.location.origin,
2932
fetchClient = fetch.bind(window),
3033
fetchOptions = {},
3134
locale = '',
3235
onError = () => {},
3336
onResponse = (r) => r,
3437
removeEmbedded = false,
35-
}) {
38+
} = {}) {
39+
this.basePath = basePath;
3640
this.baseUrl = baseUrl;
3741
this.fetchClient = fetchClient;
3842
this.fetchOptions = fetchOptions;
@@ -46,12 +50,25 @@ export default class Client {
4650
* Builds a URL with the given path and optional query parameters.
4751
*
4852
* @param {string} path - The path for the URL.
49-
* @param {Object} [params={}] - The query parameters for the URL.
50-
* @param {boolean} [withLocale=true] - Whether to prepend locale to path.
53+
* @param {Object} [options={}] - The options for building the URL.
54+
* @param {Object} [options.params={}] - The query parameters for the URL.
55+
* @param {boolean} [options.withBasePath=true] - Whether to apply the base path.
56+
* @param {boolean} [options.withLocale=true] - Whether to prepend locale to path.
5157
* @returns {URL} The built URL.
5258
*/
53-
buildUrl(path, params = {}, withLocale = true) {
54-
const url = new URL((this.locale && withLocale ? `/${this.locale}` : '') + path, this.baseUrl);
59+
buildUrl(
60+
path,
61+
{
62+
params = {},
63+
withBasePath = true,
64+
withLocale = true,
65+
} = {}
66+
) {
67+
const url = new URL([
68+
...(this.locale && withLocale ? [this.locale] : []),
69+
...(this.basePath && withBasePath ? [this.basePath] : []),
70+
path,
71+
].join('/').replaceAll('//', '/'), this.baseUrl);
5572

5673
if(params) {
5774
url.search = new URLSearchParams(params);
@@ -61,21 +78,16 @@ export default class Client {
6178
}
6279

6380
/**
64-
* Sends a request to the API with the given path and query parameters.
81+
* Sends a request to the API with the given path and URL options.
6582
*
66-
* @param {string} path - The path for the request.
67-
* @param {Object} [params] - The query parameters for the request.
68-
* @param {boolean} [withLocale] - Whether to build a localized URL.
83+
* @param {URL} url - The URL for the request.
6984
* @returns {Promise<Object>} A Promise that resolves to the request's JSON.
7085
*/
71-
async request(path, params, withLocale) {
86+
async request(url) {
7287
let response = null;
7388

7489
try {
75-
response = await this.fetchClient(
76-
this.buildUrl(path, params, withLocale).toString(),
77-
this.fetchOptions
78-
);
90+
response = await this.fetchClient(url.toString(), this.fetchOptions);
7991
} catch (error) {
8092
this.onError(error);
8193
throw error;
@@ -107,7 +119,12 @@ export default class Client {
107119
* @returns {Promise<Object>} A Promise that resolves to the page data.
108120
*/
109121
getPageByPath(path) {
110-
return this.request(`${path}.json`, null, false);
122+
return this.request(
123+
this.buildUrl(`${path}.json`, {
124+
withBasePath: false,
125+
withLocale: false,
126+
}
127+
));
111128
}
112129

113130
/**
@@ -118,7 +135,11 @@ export default class Client {
118135
* @returns {Promise<Object>} A Promise that resolves to the navigation data.
119136
*/
120137
getNavigationByKey(key, params) {
121-
return this.request(`/api/navigations/${key}`, params);
138+
return this.request(
139+
this.buildUrl(`/navigations/${key}`, {
140+
params,
141+
}
142+
));
122143
}
123144

124145
/**
@@ -129,7 +150,11 @@ export default class Client {
129150
* @returns {Promise<Object>} A Promise that resolves to the snippet area data.
130151
*/
131152
getSnippetByArea(area, params) {
132-
return this.request(`/api/snippet-areas/${area}`, params);
153+
return this.request(
154+
this.buildUrl(`/snippet-areas/${area}`, {
155+
params,
156+
})
157+
);
133158
}
134159

135160
/**
@@ -139,8 +164,12 @@ export default class Client {
139164
* @returns {Promise<Object>} A Promise that resolves to the search results.
140165
*/
141166
search(query) {
142-
return this.request('/api/search', {
143-
q: query,
144-
});
167+
return this.request(
168+
this.buildUrl('/search', {
169+
params: {
170+
q: query,
171+
},
172+
}
173+
));
145174
}
146175
}

tests/client.spec.js

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import axios from 'axios';
55
// Provide origin
66
global.window = {
77
location: {
8-
origin: 'http://127.0.0.1:3000',
8+
origin: 'http://localhost:3000',
99
},
1010
};
1111

@@ -15,26 +15,34 @@ test.describe('Client', () => {
1515

1616
// Single client for all tests
1717
test.beforeAll(async () => {
18-
client = new Client({});
18+
client = new Client();
1919
});
2020

2121
// Feature tests
2222
test('should build a correct URL without params', async () => {
23-
const url = client.buildUrl('/test');
24-
expect(url.toString()).toBe(`${client.baseUrl}/test`);
23+
const url = client.buildUrl('/test.json', {
24+
withBasePath: false,
25+
});
26+
expect(url.toString()).toBe(`${client.baseUrl}/test.json`);
2527
});
2628

2729
test('should build a correct URL with params', async () => {
28-
const url = client.buildUrl('/test', {
29-
foo: 'bar',
30-
baz: 'qux',
30+
const url = client.buildUrl('/test.json', {
31+
params: {
32+
foo: 'bar',
33+
baz: 'qux',
34+
},
35+
withBasePath: false,
3136
});
32-
expect(url.toString()).toBe(`${client.baseUrl}/test?foo=bar&baz=qux`);
37+
expect(url.toString()).toBe(`${client.baseUrl}/test.json?foo=bar&baz=qux`);
3338
});
3439

3540
test('should build a correct URL with falsy params', async () => {
36-
const url = client.buildUrl('/test', false);
37-
expect(url.toString()).toBe(`${client.baseUrl}/test`);
41+
const url = client.buildUrl('/test.json', {
42+
params: false,
43+
withBasePath: false,
44+
});
45+
expect(url.toString()).toBe(`${client.baseUrl}/test.json`);
3846
});
3947

4048
test('should transform response', async () => {

0 commit comments

Comments
 (0)