File Pointers / File ID's

Details about working with files in the dexi API

When working with files in results coming from the Dexi platform you'll not receive the entire raw file in the JSON data - but rather receive a so-called Dexi File Pointer. These are small meta-data placeholders Dexi uses to pass files around without passing the entire file around.

You will only receive Dexi file pointers in data-storage and data-filter components that allow files to be received in their inputs.

The format is as follows:

FILE:<mimetype>;<size>;<fileId>

🚧

Parsing

We might be adding more metadata values to the end of this format so if writing custom parsers you should take care not to have the parser fail if there are more values in the semicolon-seperated list of values.

As an example:

FILE:image/png;432123;BF7656AA-2D88-4248-BD05-AEB5DF9F9670

The file id is the ID of the file that's stored within Dexi and as such is subject to the same TTL rules that other data in Dexi is subject to. What that means is that if the file is part of an execution result it will automatically be deleted after 2-3 weeks.

❗️

Storing File Pointers

As a rule of thumb do not store file pointers externally but rather retrieve the data they point to and store that instead.

A simple example of how to do retrieve the contents of a file using the file id so can be found below.

package my.org.components;

import io.dexi.client.DexiClientFactory;
import io.dexi.client.DexiFileClient;
import io.dexi.service.AppContext;
import io.dexi.service.components.AppComponent;
import io.dexi.service.components.DataStorageAppComponent;
import io.dexi.service.exceptions.UserErrorException;
import io.dexi.service.utils.RowStream;
import my.org.data.MyAppConfig;
import my.org.data.MyComponentConfig;
import my.org.data.SomeRepository;

import java.io.IOException;

@AppComponent("my-app-component")
public class MyAppDataStorageAppComponent implements DataStorageAppComponent<MyAppConfig, MyComponentConfig> {

    private final SomeRepository someRepository;

    private final DexiClientFactory dexiClientFactory;

    public MyAppDataStorageAppComponent(SomeRepository someRepository, DexiClientFactory dexiClientFactory) {
        this.someRepository = someRepository;
        this.dexiClientFactory = dexiClientFactory;
    }

    @Override
    public Object write(AppContext<MyAppConfig, MyComponentConfig> ctxt, RowStream rows) throws IOException {

        //Create a dexi client for the current activation
        final DexiClientFactory.DexiClient dexiClient = dexiClientFactory.create(ctxt.getActivationId());

        //Imagine we read this from an input value
        String stringValue = "FILE:image/png;2344323;CC909360-D324-4FA6-865D-5445C771D0C8";

        //Verify the value is a file field (file pointer)
        if (DexiFileClient.isFileFieldValue(stringValue)) {
            //Get a handle for the file via the API
            final DexiFileClient.FileHandle fileHandle = dexiClient.files().getFileFromFieldValue(stringValue);

            //Can be null if file was not found
            if (fileHandle != null) {
                //Do something with the stream on the file handle
                someRepository.saveFileFromStream(fileHandle.getStream());
            } else {
                throw new UserErrorException("File not found");
            }
        } else {
            throw new UserErrorException("File pointer was not valid");
        }

        return null;
    }

    @Override
    public Class<MyComponentConfig> getComponentConfigClass() {
        return MyComponentConfig.class;
    }
}