Document import and export

# Overview

The document import/export feature allows users to export, and import entire documents including:

  • active collaborative editing session or stored content (if no active collaborative session exists and document storage is enabled),
  • comments,
  • suggestions,
  • revision history.

# Document import/export vs. collaboration import/export

There is a similar collaboration import and export feature which allows to import and export the data from the server. The main difference between those two is the fact that the document import/export allows for treating the document as one single resource providing the content, suggestions, comments, and more. The main benefit of this approach is the reduction of the number of requests that one has to perform to initialize and export all document data from the server. The second difference is that the collaboration import and export feature only operates on an active collaboration session which means the data from the document storage will not be exported. What is more, the document export feature allows obtaining document content without the suggestions/comments markers.

For example, the document export/import workflow may be the following:

  1. Import the document data or create a new collaborative editing session by connecting CKEditor 5.
  2. Collaborate on the document – add and modify content, comments, and suggestions.
  3. Export document data – save the exported document data in a client’s storage.
  4. Remove document data.

You may notice that the content exported from the collaboration import and export contains comments/suggestions markers. Bear in mind that there are only CKEditor markers there. A comment or suggestion marker requires the actual comment or suggestion object to be present in the server database. This means that if you export the content from the collaboration import and export feature and then permanently remove comments and suggestions from the database, the next document import with the usage of the collaboration import and export feature will result in a broken document. Therefore, for such a case use this document import and export feature instead.

# Export prerequisites

  • An editor bundle needs to be uploaded.
  • The exported document needs to exist in an active collaboration session or document storage.

# Export usage

Exporting the entire document means returning the data from the active collaborative editing session or the document storage (if present), as well as all document-related data like comments and suggestions. It is done by sending a request to GET /documents/{document_id} from our REST API.
You can also use the feature to quickly export the content with the suggestion or comment markers excluded without the need to modify the original document.

# Import prerequisites

  • An editor bundle needs to be uploaded.
  • The target document should exist neither in a collaboration session nor in the document storage.
  • Related comments and suggestions should not exist in the database.

# Import usage

Importing the entire document means creating a new collaborative editing session using the document data from the request body including collaborative editing session data, comments, and suggestions. It is done by sending a request to POST /documents REST API.

# Example

The example below has been prepared in Node.js.

  1. Run the following commands
mkdir cs-import-export-example && cd cs-import-export-example && npm init -y && npm i axios && touch importExport.cjs
  1. Open cs-import-export-example/importExport.cjs and paste the following code snippet:
const crypto = require( 'crypto' );
const axios = require( 'axios' );

// Update with your credentials and application endpoint
const environmentId = 'txQ9sTfqmXUyWU5LmDbr';
const apiSecret = '4zZBCQoPfRZ7Rr7TEnGAuRsGgbfF58Eg0PA8xcLD2kvPhjGjy4VGgB8k0hXn';
const applicationEndpoint = 'https://33333.cke-cs.com';

// Set document id
const documentId = 'my_document_id';

const importApiEndpoint = `${ applicationEndpoint }/api/v5/${ environmentId }/documents`;
const exportApiEndpoint = `${ applicationEndpoint }/api/v5/${ environmentId }/documents/${ documentId }`;

const importBody = {
    id: documentId,
    content: {
        bundle_version: '34.1.0',
        data: '<h2><comment-start name=\"e712d8a9d63d6f1201576ccb7c0f15a77:cd907\"></comment-start>Hello world<comment-end name=\"e712d8a9d63d6f1201576ccb7c0f15a77:cd907\"></comment-end> from <suggestion-start name=\"insertion:ed7c304a37913421ddc1d7950a144d41d:user-1\"></suggestion-start>example suggestion <suggestion-end name=\"insertion:ed7c304a37913421ddc1d7950a144d41d:user-1\"></suggestion-end>CKEditor 5!</h2>'
    },
    comments: [
        {
            id: 'e52d6b88056950a3d98ecd4f10053a74c',
            document_id: documentId,
            thread_id: 'e712d8a9d63d6f1201576ccb7c0f15a77',
            content: '<p>example comment</p>',
            attributes: {},
            updated_at: '2022-09-28T18:11:47.258Z',
            created_at: '2022-09-28T18:11:47.239Z',
            user: {
                id: 'user-1'
            },
            type: 1
        }
    ],
    suggestions: [
        {
            id: 'ed7c304a37913421ddc1d7950a144d41d',
            document_id: documentId,
            has_comments: false,
            attributes: {},
            created_at: '2022-09-28T18:11:23.726Z',
            author_id: 'user-1',
            state: 'open',
            type: 'insertion',
            requester_id: 'user-1'
        }
    ]
};

( async () => {
    await importDocument( importBody );

    const exportedData = await exportDocument();

    console.log( 'Exported data:' );
    console.log( exportedData );

    async function importDocument( body ) {
        try {
            const config = getConfig( 'POST', importApiEndpoint, body );
            const response = await axios.post( importApiEndpoint, body, config );

            console.log( response.status );

            return response.data;
        } catch ( error ) {
            console.log( error.message );
            console.log( error.response.data );
        }
    }

    async function exportDocument() {
        try {
            const config = getConfig( 'GET', exportApiEndpoint );
            const response = await axios.get( exportApiEndpoint, config );

            return response.data;
        } catch ( error ) {
            console.log( error.message );
            console.log( error.response.data );
        }
    }
} )();

function getConfig( method, url, body ) {
    const CSTimestamp = Date.now();

    return {
        headers: {
            'X-CS-Timestamp': CSTimestamp,
            'X-CS-Signature': generateSignature( apiSecret, method, url, CSTimestamp, body )
        }
    };
}

function generateSignature( secret, method, uri, timestamp, body ) {
    const url = new URL( uri );
    const path = url.pathname + url.search;
    const hmac = crypto.createHmac( 'SHA256', secret );

    hmac.update( `${ method.toUpperCase() }${ path }${ timestamp }` );

    if ( body ) {
        hmac.update( Buffer.from( JSON.stringify( body ) ) );
    }

    return hmac.digest( 'hex' );
}
  1. Update your credentials and the documentId values in the code snippet.

  2. Execute the node importExport.cjs command.

After a successful response with a status code 201 from the import request, you can open the editor with the same documentId as set in the snippet to see your imported content. Moreover, exported document content should be printed on the console.

# Troubleshooting

  • In case any operation during importing fails, e.g. fail while importing comments, all data of imported document will be revoked.
  • We suggest enabling Insight Panel, where you will find detailed logs from the whole process including exact reasons for any failed requests.

# More info

You will find more info in our REST API documentation.