Skip to main content
Version: 4.xx.xx

Audit Log Provider

Overview

refine allows you to track changes in your data and keep track of who made the changes. This is done by sending a new log event record whenever a new record is created, updated or deleted. Mutations made with data hooks are automatically sent the auditLogProvider as an event. You can also manually send events to the auditLogProvider via hooks.

An audit log provider must have the following three methods:

  • create: Logs an event to the audit log.
  • get: Returns a list of events.
  • update: Updates an event in the audit log.

Below are the corresponding interfaces for each of these methods.

const auditLogProvider = {
create: (params: {
resource: string;
action: string;
data?: any;
author?: {
name?: string;
[key: string]: any;
};
previousData?: any;
meta?: Record<string, any>;
}) => void;
get: (params: {
resource: string;
action?: string;
meta?: Record<string, any>;
author?: Record<string, any>;
metaData?: MetaDataQuery;
}) => Promise<any>;
update: (params: {
id: BaseKey;
name: string;
}) => Promise<any>;
}
note

refine provides the useLog and useLogList hooks to access your auditLogProvider methods from anywhere in your application.

Usage

You just need to pass your auditLogProvider object to <Refine>:

App.tsx
import { Refine } from "@refinedev/core";

import auditLogProvider from "./auditLogProvider";

const App: React.FC = () => {
return <Refine auditLogProvider={auditLogProvider} />;
};

Creating an Audit Log Provider

Let's create an auditLogProvider to understand better. In this example, we will use dataProvider to handle events. But you can handle events whatever you want because refine provides an agnostic API. So, If you want to use a third-party library, of course, you can.

get

This method is used to list audit log events.

For example, using useLogList hook to list all resource activities by a specific record id creates an event like this:

{
"resource": "posts",
"meta": {
"id": "1"
}
}
info

The event is create with parameters passed to the useLogList hook.

Now let's see how we can handle these events in our audit log provider.

auditLogProvider.ts
import refineSimpleRestDataProvider from "@refinedev/simple-rest";

const API_URL = "https://api.fake-rest.refine.dev";

const dataProvider = refineSimpleRestDataProvider(API_URL);

const auditLogProvider: AuditLogProvider = {
get: async ({ resource, meta }) => {
const { data } = await dataProvider(API_URL).getList({
resource: "logs",
filters: [
{
field: "resource",
operator: "eq",
value: resource,
},
{
field: "meta.id",
operator: "eq",
value: meta?.id,
},
],
});

return data;
},
};

Parameter Types

This method can take the following parameters via hooks. You can use these parameters to filter the events.

NameType
resourcestring
action"create" | "update" | "delete" | "createMany" | "updateMany" | "deleteMany" | string
metaRecord<string, any>
authorRecord<string, any>

create

This method is used to create an audit log event. It is triggered when a new successful mutation or when you use useLog's log method. The incoming parameters show the values of the new record to be created.

caution

We recommend you create audit logs on the API side for security concerns because data can be changed on the client side.

When the mutations is successful, the create method is called with the following parameters, depending on the mutation type:

When a record is created, refine automatically sends an event to create method like this:

{
"action": "create",
"resource": "posts",
"data": {
"title": "Hello World",
"content": "Hello World"
},
"meta": {
"dataProviderName": "simple-rest",
// If request response has a `id` field, it will be add in the `meta` field.
"id": 1
}
}
info

The id of the created record is added to the meta object. It can be used for filtering purposes.

tip

If getUserIdentity is defined in your auth provider, the author object is added to the event with the value returned by getUserIdentity.


Now let's see how we can handle these events in our audit log provider.

auditLogProvider.ts
import refineSimpleRestDataProvider from "@refinedev/simple-rest";

const API_URL = "https://api.fake-rest.refine.dev";

const dataProvider = refineSimpleRestDataProvider(API_URL);

const auditLogProvider: AuditLogProvider = {
create: (params) => {
return dataProvider(API_URL).create({
resource: "logs",
variables: params,
});
},
};

Parameter Types

This method can take the following parameters.

NameType
resourcestring
action"create" | "update" | "delete" | "createMany" | "updateMany" | "deleteMany" | string
metaRecord<string, any>
dataRecord<string, any>
authorRecord<string, any>

info

refine will use this create method in the useLog hook.

Refer to the useLog documentation for more information. &#8594

update

This method is used to update an audit log event.

tip

If you want to name an event, this is the way to do it. You can create a milestone by naming it.

For example, using useLog's log method creates an event like below:

{
"id": "1",
"name": "event name"
}
auditLogProvider.ts
import refineSimpleRestDataProvider from "@refinedev/simple-rest";

const API_URL = "https://api.fake-rest.refine.dev";

const dataProvider = refineSimpleRestDataProvider(API_URL);

const auditLogProvider: AuditLogProvider = {
update: async ({ id, name }) => {
const { data } = await dataProvider(API_URL).update({
resource: "logs",
id,
variables: { name },
});
return data;
},
};

Parameter Types

This method can take the following parameters.

NameType
idBaseKey
namestring

info

refine will use this update method in the useLog hook.

Refer to the useLog documentation for more information. &#8594

Supported Hooks

refine creates an audit log event when the mutation is successful on hooks that useCreate, useUpdate, useDelete, useCreateMany, useUpdateMany and useDeleteMany hooks.

useCreate

When useCreate is called, refine sends the following parameters to audit log provider's create method.

const { mutate } = useCreate();

mutate({
resource: "posts",
values: {
title: "New Post",
status: "published",
content: "New Post Content",
},
metaData: {
foo: "bar",
},
});
Create event
{
"action": "create",
"resource": "posts",
"data": {
"title": "Title",
"status": "published",
"content": "New Post Content"
},
"meta": {
"id": "1",
// `metaData` is included in `meta`.
"foo": "bar"
}
}

useCreateMany

When useCreateMany is called, refine sends the following parameters to audit log provider's create method.

const { mutate } = useCreateMany();

mutate({
resource: "posts",
values: [
{
"title": "Title1",
"status": "published",
"content": "New Post Content1"
},
{
"title": "Title2",
"status": "published",
"content": "New Post Content2"
}
],
metaData: {
foo: "bar",
},
});
CreateMany event
{
"action": "createMany",
"resource": "posts",
"data": [
{
"title": "Title1",
"status": "published",
"content": "New Post Content1"
},
{
"title": "Title2",
"status": "published",
"content": "New Post Content2"
}
],
"meta": {
"ids": [1, 2],
// `metaData` is included in `meta`.
"foo": "bar"
}
}

useUpdate

When useUpdate is called, refine sends the following parameters to audit log provider's create method.

const { mutate } = useUpdate();

mutate({
id: 1,
resource: "posts",
values: {
title: "Updated New Title",
},
});
Update event
{
"action": "update",
"resource": "posts",
"data": {
"title": "Updated New Title",
"status": "published",
"content": "New Post Content"
},
"previousData": {
"title": "Title",
"status": "published",
"content": "New Post Content"
},
"meta": {
"id": 1
}
}

useUpdateMany

When useUpdateMany is called, refine sends the following parameters to audit log provider's create method.

const { mutate } = useUpdateMany();

mutate({
ids: [1, 2],
resource: "posts",
values: {
title: "Updated New Title",
},
});
UpdateMany event
{
"action": "updateMany",
"resource": "posts",
"data": {
"title": "Updated New Title",
},
"previousData": [
{
"title": "Title1",
},
{
"title": "Title2",
}
],
"meta": {
"ids": [1, 2]
}
}

useDelete

When useDelete is called, refine sends the following parameters to audit log provider's create method.

const { mutate } = useDelete();

mutate({
id: 1,
resource: "posts",
});
Delete event
{
"action": "delete",
"resource": "posts",
"meta": {
"id": 1
}
}

useDeleteMany

When useDeleteMany is called, refine sends the following parameters to audit log provider's create method.

const { mutate } = useDeleteMany();

mutate({
ids: [1, 2],
resource: "posts",
});
DeleteMany event
{
"action": "deleteMany",
"resource": "posts",
"meta": {
"ids": [1, 2]
}
}

Enable/Disable to Audit Log by Mutation Type for a Resource

The meta.audit allows you to manage the audit log events for a resource. In addition, it can be managed in which type of mutations an event will be created. If no definition is made, it works in all actions.

In this case, only events will be created for the create mutation.

App.tsx
<Refine
dataProvider={dataProvider(API_URL)}
resources={[
{
name: "posts",
list: PostList,
create: PostCreate,
edit: PostEdit,
show: PostShow,
canDelete: true,
meta: {
audit: ["create"],
},
},
]}
/>

Example

RUN IN YOUR LOCAL
npm create refine-app@latest -- --example audit-log-provider