Skip to content

Commit 4182680

Browse files
udimbertopwizla
andauthored
Add an interactive query builder (#1714)
* internal: dev docs - rest API parameters - interactive query builder * Describe usage of interactive query builder * Prettify URLs * Improve instructions * Update the tip in the REST API parameters page * Add a default hint to the Endpoint field * Add the Interactive Query Builder page * Fine-tune wording in callouts * Update: Interactive Query Builder - Query String URL field as 'textarea' * Update disclaimer wording --------- Co-authored-by: Pierre Wizla <[email protected]> Co-authored-by: Pierre Wizla <[email protected]>
1 parent 639c0c6 commit 4182680

23 files changed

+495
-44
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
title: Interactive Query Builder
3+
description: Use an interactive tool that leverages the querystring library to build your query URL
4+
displayed_sidebar: devDocsSidebar
5+
---
6+
7+
# Build your query URL with Strapi's interactive tool
8+
9+
A wide range of parameters can be used and combined to query your content with the [REST API](/dev-docs/api/rest), which can result in long and complex query URLs.
10+
11+
Strapi's codebase uses [the `qs` library](https://github.com/ljharb/qs) to parse and stringify nested JavaScript objects. It's recommended to use `qs` directly to generate complex query URLs instead of creating them manually.
12+
13+
You can use the following interactive query builder tool to generate query URLs automatically:
14+
15+
1. Replace the values in the _Endpoint_ and _Endpoint Query Parameters_ fields with content that fits your needs.
16+
2. Click the **Copy to clipboard** button to copy the automatically generated _Query String URL_ which is updated as you type.
17+
18+
:::info Parameters usage
19+
Please refer to the [REST API parameters table](/dev-docs/api/rest/parameters) and read the corresponding parameters documentation pages to better understand parameters usage.
20+
:::
21+
22+
<br />
23+
24+
<InteractiveQueryBuilder
25+
endpoint="/api/books"
26+
code={`
27+
{
28+
sort: ['title:asc'],
29+
filters: {
30+
title: {
31+
$eq: 'hello',
32+
},
33+
},
34+
populate: '*',
35+
fields: ['title'],
36+
pagination: {
37+
pageSize: 10,
38+
page: 1,
39+
},
40+
publicationState: 'live',
41+
locale: ['en'],
42+
}
43+
`}
44+
/>
45+
46+
<br />
47+
48+
<br />
49+
50+
:::note
51+
The default endpoint path is prefixed with `/api/` and should be kept as-is unless you configured a different API prefix using [the `rest.prefix` API configuration option](/dev-docs/configurations/api).<br/> For instance, to query the `books` collection type using the default API prefix, type `/api/books` in the _Endpoint_ field.
52+
:::
53+
54+
:::caution Disclaimer
55+
The `qs` library and the interactive query builder provided on this page:
56+
- might not detect all syntax errors,
57+
- are not aware of the parameters and values available in a Strapi project,
58+
- and do not provide autocomplete features.
59+
60+
Currently, these tools are only provided to transform the JavaScript object in an inline query string URL. Using the generated query URL does not guarantee that proper results will get returned with your API.
61+
:::
Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Parameters
2+
title: Parameters
33
description: Use API parameters to refine your Strapi REST API queries.
44

55
next: ./filtering-locale-publication.md
@@ -26,37 +26,5 @@ The following API parameters are available:
2626
Query parameters use the LHS bracket syntax (i.e. they are encoded using square brackets `[]`)
2727

2828
:::tip
29-
<QsIntroShort />
30-
31-
<details>
32-
<summary>Example using qs:</summary>
33-
34-
In the following example, the `qs` library is used to build the following URL:
35-
`/api/books?sort[0]=title%3Aasc&filters[title][$eq]=hello&populate=%2A&fields[0]=title&pagination[pageSize]=10&pagination[page]=1&publicationState=live&locale[0]=en`
36-
37-
```js
38-
const qs = require('qs');
39-
const query = qs.stringify({
40-
sort: ['title:asc'],
41-
filters: {
42-
title: {
43-
$eq: 'hello',
44-
},
45-
},
46-
populate: '*',
47-
fields: ['title'],
48-
pagination: {
49-
pageSize: 10,
50-
page: 1,
51-
},
52-
publicationState: 'live',
53-
locale: ['en'],
54-
}, {
55-
encodeValuesOnly: true, // prettify URL
56-
});
57-
58-
await request(`/api/books?${query}`);
59-
```
60-
61-
</details>
29+
A wide range of REST API parameters can be used and combined to query your content, which can result in long and complex query URLs.<br/>👉 You can use Strapi's [interactive query builder](/dev-docs/api/rest/interactive-query-builder) tool to build query URLs more conveniently. 🤗
6230
:::
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Strapi takes advantage of the ability of the [`qs`](https://github.com/ljharb/qs) library to parse nested objects to create more complex queries.
1+
Strapi takes advantage of the ability of [the `qs` library](https://github.com/ljharb/qs) to parse nested objects to create more complex queries.
22
Use `qs` directly to generate complex queries instead of creating them manually.

docusaurus/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"embla-carousel-react": "^7.1.0",
2828
"embla-carousel-wheel-gestures": "^3.0.0",
2929
"prism-react-renderer": "^1.3.5",
30+
"qs": "^6.11.1",
3031
"react": "^17.0.2",
3132
"react-dom": "^17.0.2",
3233
"redocusaurus": "^1.6.1",

docusaurus/sidebars.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ const sidebars = {
159159
'dev-docs/api/rest/filters-locale-publication',
160160
'dev-docs/api/rest/sort-pagination',
161161
'dev-docs/api/rest/relations',
162+
'dev-docs/api/rest/interactive-query-builder',
162163
]
163164
},
164165
'dev-docs/api/graphql',

docusaurus/src/components/Button/Button.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export function Button({
2222
{...(!to ? {} : { to })}
2323
className={clsx(
2424
'button',
25-
(variant && `button--${variant}`),
25+
(variant && styles[`button--${variant}`]),
2626
(size && styles[`button--${size}`]),
2727
styles.button,
2828
styles[variant],

docusaurus/src/components/Button/button.module.scss

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
/** Component: Button */
22

3+
@import '../../scss/_mixins.scss';
4+
35
.button {
46
--strapi-button-background-color: var(--strapi-primary-600);
7+
--strapi-button-border-color: var(--strapi-primary-600);
58
--strapi-button-border-radius: 4px;
69
--strapi-button-box-shadow: 0 0 0 transparent;
710
--strapi-button-color: #fff;
@@ -13,13 +16,22 @@
1316
--strapi-button-px: 15px;
1417
--strapi-button-transition-property: color, background, border-color, box-shadow;
1518

19+
--strapi-button-hover-background-color: var(--strapi-primary-700);
20+
--strapi-button-hover-border-color: var(--strapi-primary-700);
21+
--strapi-button-hover-box-shadow: 0px 9px 10px rgba(44, 56, 148, 0.2475);
22+
--strapi-button-hover-color: #fff;
23+
1624
--ifm-button-color: var(--strapi-button-color);
25+
--ifm-button-background-color: var(--strapi-button-background-color);
26+
--ifm-button-border-color: var(--strapi-button-border-color);
1727
--ifm-button-border-radius: var(--strapi-button-border-radius);
1828
--ifm-button-font-weight: var(--strapi-button-font-weight);
1929
--ifm-button-padding-horizontal: var(--strapi-button-px);
2030
--ifm-button-padding-vertical: var(--strapi-button-py);
2131
--ifm-button-size-multiplier: 1;
2232

33+
--ifm-color-primary-darker: var(--strapi-primary-200);
34+
2335
--ifm-link-hover-color: var(--strapi-button-color);
2436
--ifm-link-hover-decoration: none;
2537

@@ -37,8 +49,14 @@
3749
right: -8px;
3850
}
3951

40-
&:focus, &:hover {
41-
--strapi-button-box-shadow: 0px 9px 10px rgba(44, 56, 148, 0.2475);
52+
&:not(:disabled),
53+
&:not([aria-disabled="true"]) {
54+
&:focus, &:hover {
55+
--strapi-button-box-shadow: var(--strapi-button-hover-box-shadow);
56+
--strapi-button-background-color: var(--strapi-button-hover-background-color);
57+
--strapi-button-border-color: var(--strapi-button-hover-border-color);
58+
--strapi-button-color: var(--strapi-button-hover-color);
59+
}
4260
}
4361

4462
/** Sizes */
@@ -49,4 +67,30 @@
4967
--strapi-button-py: 11px;
5068
--strapi-button-px: 71px;
5169
}
70+
71+
/** Variants */
72+
&--secondary {
73+
--strapi-button-background-color: #f0f0ff;
74+
--strapi-button-border-color: #d9d8ff;
75+
--strapi-button-color: var(--strapi-primary-600);
76+
77+
--strapi-button-hover-background-color: var(--strapi-neutral-0);
78+
--strapi-button-hover-border-color: #d9d8ff;
79+
--strapi-button-hover-box-shadow: none;
80+
--strapi-button-hover-color: var(--strapi-primary-600);
81+
}
82+
}
83+
84+
/** Dark mode */
85+
@include dark {
86+
.button {
87+
/** Dark mode Variants */
88+
&--secondary {
89+
--strapi-button-background-color: var(--strapi-neutral-100);
90+
--strapi-button-border-color: var(--strapi-neutral-200);
91+
92+
--strapi-button-hover-background-color: var(--strapi-neutral-0);
93+
--strapi-button-hover-border-color: var(--strapi-neutral-200);
94+
}
95+
}
5296
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import React from 'react';
2+
import clsx from 'clsx';
3+
import styles from './form-field.module.scss';
4+
import { FormFieldHint } from '../FormFieldHint/FormFieldHint';
5+
import { FormFieldInput } from '../FormFieldInput/FormFieldInput';
6+
import { FormFieldLabel } from '../FormFieldLabel/FormFieldLabel';
7+
8+
export function FormField({
9+
children,
10+
className,
11+
id,
12+
13+
// Optional - Object which contains Input props
14+
input,
15+
16+
// Optional - Simple String or an Object which contains 'FormFieldLabel' props
17+
label,
18+
19+
// Optional - Simple String or an Object which contains 'FormFieldHint' props
20+
hint,
21+
22+
...rest
23+
}) {
24+
return (
25+
<fieldset
26+
{...rest}
27+
id={`${id}-wrapper`}
28+
className={clsx(
29+
styles['form-field'],
30+
className,
31+
)}
32+
>
33+
{label && (
34+
<FormFieldLabel
35+
id={`${id}-label`}
36+
htmlFor={id}
37+
{...((typeof label === 'object') ? label : { children: label })}
38+
/>
39+
)}
40+
{input && (
41+
<FormFieldInput
42+
id={id}
43+
{...input}
44+
/>
45+
)}
46+
{children}
47+
{hint && (
48+
<FormFieldHint
49+
id={`${id}-hint`}
50+
htmlFor={id}
51+
{...((typeof hint === 'object') ? hint : { children: hint })}
52+
/>
53+
)}
54+
</fieldset>
55+
);
56+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/** Component: Form Field */
2+
3+
.form-field {
4+
display: var(--strapi-form-field-input-display, block);
5+
width: var(--strapi-form-field-input-width, 100%);
6+
border: var(--strapi-form-field-border, 0);
7+
margin: var(--strapi-form-field-my, var(--strapi-spacing-4)) var(--strapi-form-field-mx, 0);
8+
padding: var(--strapi-form-field-py, 0) var(--strapi-form-field-px, 0);
9+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from 'react';
2+
import clsx from 'clsx';
3+
import styles from './form-field-hint.module.scss';
4+
5+
export function FormFieldHint({
6+
className,
7+
...rest
8+
}) {
9+
return (
10+
<label
11+
{...rest}
12+
className={clsx(
13+
styles['form-field__hint'],
14+
className,
15+
)}
16+
/>
17+
);
18+
}

0 commit comments

Comments
 (0)