Skip to main content
Version: 2.xx.xx

Strapi-v4

refine supports the features that come with Strapi-v4.

A few of the Strapi-v4 API features are as follows:

  • Fields Selection
  • Relations Population
  • Publication State
  • Locale

You can use these API features with refine. Thanks to MetaDataQuery, you can simply send queries using these API parameters.

Hooks and components that support MetaDataQuery:

Supported data hooksSupported other hooksSupported components
useUpdate โ†’useForm โ†’DeleteButton โ†’
useUpdateMany โ†’useModalForm โ†’RefreshButton โ†’
useDelete โ†’useDrawerForm โ†’
useDeleteMany โ†’useStepsForm โ†’
useCreate โ†’useTable โ†’
useCreateMany โ†’useEditableTable โ†’
useList โ†’useSimpleList โ†’
useOne โ†’useShow โ†’
useMany โ†’useExport โ†’
useCustom โ†’useCheckboxGroup โ†’
useSelect โ†’
useRadioGroup โ†’
note

You can handle features such as Sorting, Pagination and Filters with Dataprovider. There is no need to use MetaDataQuery.

Setup

npm i @pankod/refine-strapi-v4

Usage

App.tsx
import { Refine, AuthProvider } from "@pankod/refine";
import { DataProvider } from "@pankod/refine-strapi-v4";
import routerProvider from "@pankod/refine-react-router";

const App: React.FC = () => {
return (
<Refine
authProvider={authProvider}
dataProvider={DataProvider("API_URL")}
routerProvider={routerProvider}
/>
);
};

API Parameters

Let's examine how API parameters that come with Strapi-v4 are used with refine metadata. Then, let's see how it is used in the application.

Create Collections

We created two collections on Strapi as posts and categories and added a relation between them. For detailed information on how to create a collection, you can check here.

posts
{
id: 3,
attributes: {
title: "Incidunt tempora ut voluptas est",
content: "Soluta voluptatibus rem assumenda id autem possimus dicta molestiae qui. Tenetur corporis sed aliquam et voluptatibus expedita in sunt.",
createdAt: "2021-12-15T14:22:52.919Z",
updatedAt: "2021-12-15T14:23:07.542Z",
publishedAt: "2021-12-15T14:22:54.126Z",
locale: "en"
}
}

Fields Selection

To select only some fields, we must specify this fields with metadata.

Refer to the Fields Selection documentation for detailed information. โ†’

Get only id and title of all posts
const { tableProps } = useTable<IPost>({
metaData: {
fields: ["id", "title"]
},
});
Get all fields of all posts(id, title, category, content ...)
const { tableProps } = useTable<IPost>({
metaData: {
fields: "*"
},
});

When sending the request, we can specify which fields will come, so we send fields in metaData to hooks that we will fetch data from. In this way, you can perform the queries of only the fields you want.

PostList.tsx
import { useState } from "react";
import {
List,
Table,
useTable,
IResourceComponentsProps,
getDefaultSortOrder,
FilterDropdown,
Select,
useSelect,
Space,
EditButton,
DeleteButton,
} from "@pankod/refine";

import { IPost } from "interfaces";

import { API_URL } from "../../constants";

export const PostList: React.FC<IResourceComponentsProps> = () => {
const { tableProps, sorter } = useTable<IPost>({
metaData: {
fields: ["id", "title"],
},
});

return (
<List>
<Table
{...tableProps}
rowKey="id"
pagination={{
...tableProps.pagination,
showSizeChanger: true,
}}
>
<Table.Column
dataIndex="id"
key="id"
title="ID"
defaultSortOrder={getDefaultSortOrder("id", sorter)}
sorter={{ multiple: 3 }}
/>
<Table.Column
dataIndex="title"
key="title"
title="Title"
defaultSortOrder={getDefaultSortOrder("title", sorter)}
sorter={{ multiple: 2 }}
/>

<Table.Column<{ id: string }>
title="Actions"
dataIndex="actions"
render={(_, record) => (
<Space>
<EditButton
hideText
size="small"
recordItemId={record.id}
/>
<DeleteButton
hideText
size="small"
recordItemId={record.id}
/>
</Space>
)}
/>
</Table>
</List>
);
};
Fields Selection Metadata

Relations Population

By default, relations are not populated when fetching entries.

The populate parameter is used to define which fields will be populated.

Refer to the Relations Population documentation for detailed information. โ†’

Get all the posts and populate the selected relations
const { tableProps } = useTable<IPost>({
metaData: {
populate: ["category", "cover"]
},
});
Get all posts and populate all their first-level relations
const { tableProps } = useTable<IPost>({
metaData: {
populate: "*"
},
});

In order to pull the categories related to the posts, we can now show the categories in our list by defining the metadata populate parameter.

PostList.tsx
import { useState } from "react";
import {
List,
Table,
useTable,
IResourceComponentsProps,
getDefaultSortOrder,
FilterDropdown,
Select,
useSelect,
DateField,
Space,
EditButton,
DeleteButton,
ImageField,
Form,
Radio,
Tag,
} from "@pankod/refine";

import { IPost } from "interfaces";

import { API_URL } from "../../constants";

export const PostList: React.FC<IResourceComponentsProps> = () => {
const [locale, setLocale] = useState("en");
const [publicationState, setPublicationState] = useState("live");

const { tableProps, sorter } = useTable<IPost>({
metaData: {
fields: ["id", "title"],
populate: ["category"],
},
});

const { selectProps } = useSelect({
resource: "categories",
optionLabel: "title",
optionValue: "id",
});

return (
<List>
<Table
{...tableProps}
rowKey="id"
pagination={{
...tableProps.pagination,
showSizeChanger: true,
}}
>
<Table.Column
dataIndex="id"
key="id"
title="ID"
defaultSortOrder={getDefaultSortOrder("id", sorter)}
sorter={{ multiple: 3 }}
/>
<Table.Column
dataIndex="title"
key="title"
title="Title"
defaultSortOrder={getDefaultSortOrder("title", sorter)}
sorter={{ multiple: 2 }}
/>
<Table.Column
key="[category][id]"
dataIndex={["category", "data", "attributes", "title"]}
title="Category"
filterDropdown={(props) => (
<FilterDropdown {...props}>
<Select
style={{ minWidth: 200 }}
mode="multiple"
placeholder="Select Category"
{...selectProps}
/>
</FilterDropdown>
)}
/>
<Table.Column<{ id: string }>
title="Actions"
dataIndex="actions"
render={(_, record) => (
<Space>
<EditButton
hideText
size="small"
recordItemId={record.id}
/>
<DeleteButton
hideText
size="small"
recordItemId={record.id}
/>
</Space>
)}
/>
</Table>
</List>
);
};
category

Publication State

note

The Draft & Publish feature should be enabled on Strapi.

Refer to the Publication State documentation for detailed information. โ†’

live: returns only published entries

preview: returns draft and published entries

const { tableProps } = useTable<IPost>({
metaData: {
publicationState: "preview"
},
});

We can list the posts separately according to the published or draft information.

PostList
import { useState } from "react";
import {
List,
Table,
useTable,
IResourceComponentsProps,
getDefaultSortOrder,
FilterDropdown,
Select,
useSelect,
DateField,
Space,
EditButton,
DeleteButton,
ImageField,
Form,
Radio,
Tag,
} from "@pankod/refine";

import { IPost } from "interfaces";

import { API_URL } from "../../constants";

export const PostList: React.FC<IResourceComponentsProps> = () => {
const [publicationState, setPublicationState] = useState("live");

const { tableProps, sorter } = useTable<IPost>({
metaData: {
fields: ["id", "title"],
populate: ["category"],
publicationState,
},
});

const { selectProps } = useSelect({
resource: "categories",
optionLabel: "title",
optionValue: "id",
});

return (
<List>
<Form
layout="inline"
initialValues={{
publicationState,
}}
>
<Form.Item label="Publication State" name="publicationState">
<Radio.Group
onChange={(e) => setPublicationState(e.target.value)}
>
<Radio.Button value="live">Published</Radio.Button>
<Radio.Button value="preview">
Draft and Published
</Radio.Button>
</Radio.Group>
</Form.Item>
</Form>
<br />
<Table
{...tableProps}
rowKey="id"
pagination={{
...tableProps.pagination,
showSizeChanger: true,
}}
>
<Table.Column
dataIndex="id"
key="id"
title="ID"
defaultSortOrder={getDefaultSortOrder("id", sorter)}
sorter={{ multiple: 3 }}
/>
<Table.Column
dataIndex="title"
key="title"
title="Title"
defaultSortOrder={getDefaultSortOrder("title", sorter)}
sorter={{ multiple: 2 }}
/>
<Table.Column
key="[category][id]"
dataIndex={["category", "data", "attributes", "title"]}
title="Category"
filterDropdown={(props) => (
<FilterDropdown {...props}>
<Select
style={{ minWidth: 200 }}
mode="multiple"
placeholder="Select Category"
{...selectProps}
/>
</FilterDropdown>
)}
/>
<Table.Column
dataIndex="publishedAt"
title="Status"
render={(value) => {
return (
<Tag color={value ? "green" : "blue"}>
{value ? "Published" : "Draft"}
</Tag>
);
}}
/>
<Table.Column<{ id: string }>
title="Actions"
dataIndex="actions"
render={(_, record) => (
<Space>
<EditButton
hideText
size="small"
recordItemId={record.id}
/>
<DeleteButton
hideText
size="small"
recordItemId={record.id}
/>
</Space>
)}
/>
</Table>
</List>
);
};
publication

Locale

tip

To fetch content for a locale, make sure it has been already added to Strapi in the admin panel

Refer to the Locale documentation for detailed information. โ†’

const { tableProps } = useTable<IPost>({
metaData: {
locale: "de"
},
});

With the local parameter feature, we can fetch posts and categories created according to different languages.

import { useState } from "react";
import {
List,
Table,
useTable,
IResourceComponentsProps,
getDefaultSortOrder,
FilterDropdown,
Select,
useSelect,
Space,
EditButton,
DeleteButton,
Form,
Radio,
Tag,
} from "@pankod/refine";

import { IPost } from "interfaces";

import { API_URL } from "../../constants";

export const PostList: React.FC<IResourceComponentsProps> = () => {
const [locale, setLocale] = useState("en");
const [publicationState, setPublicationState] = useState("live");

const { tableProps, sorter } = useTable<IPost>({
metaData: {
populate: ["category", "cover"],
locale,
publicationState,
},
});

const { selectProps } = useSelect({
resource: "categories",
optionLabel: "title",
optionValue: "id",
metaData: { locale },
});

return (
<List>
<Form
layout="inline"
initialValues={{
locale,
publicationState,
}}
>
<Form.Item label="Locale" name="locale">
<Radio.Group onChange={(e) => setLocale(e.target.value)}>
<Radio.Button value="en">English</Radio.Button>
<Radio.Button value="de">Deutsch</Radio.Button>
</Radio.Group>
</Form.Item>
<Form.Item label="Publication State" name="publicationState">
<Radio.Group
onChange={(e) => setPublicationState(e.target.value)}
>
<Radio.Button value="live">Published</Radio.Button>
<Radio.Button value="preview">
Draft and Published
</Radio.Button>
</Radio.Group>
</Form.Item>
</Form>
<br />
<Table
{...tableProps}
rowKey="id"
pagination={{
...tableProps.pagination,
showSizeChanger: true,
}}
>
<Table.Column
dataIndex="id"
key="id"
title="ID"
defaultSortOrder={getDefaultSortOrder("id", sorter)}
sorter={{ multiple: 3 }}
/>
<Table.Column
dataIndex="title"
key="title"
title="Title"
defaultSortOrder={getDefaultSortOrder("title", sorter)}
sorter={{ multiple: 2 }}
/>
<Table.Column
key="[category][id]"
dataIndex={["category", "data", "attributes", "title"]}
title="Category"
filterDropdown={(props) => (
<FilterDropdown {...props}>
<Select
style={{ minWidth: 200 }}
mode="multiple"
placeholder="Select Category"
{...selectProps}
/>
</FilterDropdown>
)}
/>
<Table.Column
dataIndex="publishedAt"
title="Status"
render={(value) => {
return (
<Tag color={value ? "green" : "blue"}>
{value ? "Published" : "Draft"}
</Tag>
);
}}
/>
<Table.Column<{ id: string }>
title="Actions"
dataIndex="actions"
render={(_, record) => (
<Space>
<EditButton
hideText
size="small"
recordItemId={record.id}
/>
<DeleteButton
hideText
size="small"
recordItemId={record.id}
/>
</Space>
)}
/>
</Table>
</List>
);
};
locale

tip

When creating and editing posts you can use these API parameters in metaData. You can look how it is used in EditList and CreateList from Codesandbox.

const { formProps, saveButtonProps, queryResult } = useForm<IPost>({
metaData: { publicationState: "preview" },
});
EditList.tsx
const { formProps, saveButtonProps, queryResult } = useForm<IPost>({
metaData: { populate: ["category", "cover"] },
});
CreateList.tsx
const { selectProps } = useSelect({
metaData: { locale: "en" },
});

Live Codesandbox Example

Username: demo@refine.dev

Password: demodemo