Skip to main content

Store user-generated data

  • How-to
  • 4 minutes

If your app allows the user to save user-generated data that needs to be available across multiple user sessions, our document service is your best option. One example of such user-defined data is to-do items that the user enters in a Todo app. This guide explains how you can store, update, and delete data from the document service.

In the following examples, you'll see two code snippets for each type of operation.

  • The React hook version uses the @dynatrace-sdk/react-hooks package for all the operations. You can use this in your React frontend code.
  • The Client SDK version uses the @dynatrace-sdk/client-document) package for all the operations. The example code shown uses this package in an app function. You can use the same code in Notebook, Dashboard, and Workflow as well.

Create a document

To create a document, use the useCreateDocument hook. This hook provides an execute function that you can use to create a new document. It also provides some additional fields with information about the loading status, errors, and the response. These fields are common to all the document hooks. The example below shows how to create a Todo list document:

import React from 'react';
import { useCreateDocument } from '@dynatrace-sdk/react-hooks';
import { Button } from '@dynatrace/strato-components/buttons';
import { Page } from '@dynatrace/strato-components-preview/layouts';

const todos = [
{
title: 'Send email to John about vacation',
done: false,
},
{
title: 'Plan workshop for next week',
done: false,
},
];

export const App = () => {
const { execute, data, error, isLoading } = useCreateDocument();

const handleClick = () => {
execute({
body: {
name: 'My Todos',
type: 'TodoList',
content: new Blob([JSON.stringify(todos)], {
type: 'application/json',
}),
},
});
};

return (
<Page>
<Page.Main>
<Button onClick={handleClick}>Create Todos</Button>
</Page.Main>
</Page>
);
};
Tip

This operation requires the scope document:documents:write. Read more about scopes in this guide.

List documents

The useListDocuments hook lets you to get a filtered list of the available documents. Besides the common fields, this hook also provides a refetch function to refetch the list of documents. The following code fetches the documents of type TodoList.

import React from 'react';
import { useListDocuments } from '@dynatrace-sdk/react-hooks';
import { Button } from '@dynatrace/strato-components/buttons';
import { List, Text } from '@dynatrace/strato-components/typography';
import { Page } from '@dynatrace/strato-components-preview/layouts';

export const App = () => {
const { data, refetch } = useListDocuments({
filter: `type == 'TodoList'`,
});

const handleClick = () => {
refetch().then((list) => console.log(list.documents));
};

return (
<Page>
<Page.Main>
{data && (
<List>
{data.documents.map((doc) => (
<Text key={doc.id}>{doc.name}</Text>
))}
</List>
)}
<Button onClick={handleClick}>Refetch Todos</Button>
</Page.Main>
</Page>
);
};
Tip

This operation requires the scope document:documents:read. Read more about scopes in this guide.

Get document content

To retrieve the content of a specific document, you can use the useDownloadDocument hook. This hook expects the document ID as a parameter and returns binary data with the document's contents, which you can extract by calling the get function. This example shows how to fetch the content for the Todo list document that we created in the first step:

import React, { useState, useEffect } from 'react';
import { useDownloadDocument } from '@dynatrace-sdk/react-hooks';
import { Page } from '@dynatrace/strato-components-preview/layouts';
import { Checkbox } from '@dynatrace/strato-components-preview/forms';

interface Todo {
title: string;
done: boolean;
}

export const App = () => {
const [todos, setTodos] = useState<Todo[]>();
const { data } = useDownloadDocument({
id: 'ff96e29d-2622-48f0-8c88-b2f20b2cf532',
});

useEffect(() => {
if (data) {
data.get('json').then((todos) => {
setTodos(todos);
});
}
}, [data]);

return (
<Page>
<Page.Main>
{todos &&
todos.map((todo) => (
<Checkbox key={todo.title} name="done" defaultValue={todo.done}>
{todo.title}
</Checkbox>
))}
</Page.Main>
</Page>
);
};
Tip

This operation requires the scope document:documents:read. Read more about scopes in this guide.

Update document

Whenever you need to change the contents of a document, use the useUpdateDocument or the useUpdateDocumentMetadata hooks. For all modifying operations, keep optimistic locking in mind. Every document has a version that's incremented whenever its metadata or content is modified. For every modifying operation, you have to pass this exact version, which you can retrieve with the useDocumentMetadata hook. It could look like the following:

import React from 'react';
import { useDocumentMetaData, useUpdateDocument } from '@dynatrace-sdk/react-hooks';
import { Button } from '@dynatrace/strato-components/buttons';
import { Page } from '@dynatrace/strato-components-preview/layouts';

const updatedTodos = [
{
title: 'Send e-mail to John concerning vacation',
done: true,
},
{
title: 'Plan workshop for next week',
done: false,
},
];

export const App = () => {
const metadata = useDocumentMetaData({
id: 'ff96e29d-2622-48f0-8c88-b2f20b2cf532',
});
const { execute } = useUpdateDocument();

const handleClick = () => {
if (metadata.data) {
execute({
id: metadata.data.id,
optimisticLockingVersion: metadata.data.version,
body: {
content: new Blob([JSON.stringify(updatedTodos)], {
type: 'application/json',
}),
},
});
}
};

return (
<Page>
<Page.Main>
<Button onClick={handleClick}>Update Todos</Button>
</Page.Main>
</Page>
);
};
Tip

This operation requires the scope document:documents:write. Read more about scopes in this guide.

Delete document

You can delete documents as well. To do so, use the useDeleteDocument hook. To delete a document, you need to provide the optimistic locking version of the document you want to delete. To delete the document we created in the first step, your code should look like this:

import React from 'react';
import { useDocumentMetaData, useDeleteDocument } from '@dynatrace-sdk/react-hooks';
import { Button } from '@dynatrace/strato-components/buttons';
import { Page } from '@dynatrace/strato-components-preview/layouts';

export const App = () => {
const metadata = useDocumentMetaData({
id: 'ff96e29d-2622-48f0-8c88-b2f20b2cf532',
});
const { execute } = useDeleteDocument();

const handleClick = () => {
if (metadata.data) {
execute({
id: metadata.data.id,
optimisticLockingVersion: metadata.data.version,
});
}
};

return (
<Page>
<Page.Main>
<Button onClick={handleClick}>Delete Todos</Button>
</Page.Main>
</Page>
);
};
Tip

This operation requires the scope document:documents:delete. Read more about scopes in this guide.

Still have questions?
Find answers in the Dynatrace Community