6

I'm using AWS SDK (v3) in my NodeJS/Typescript application, specifically their DynamoDBDocumentClient to easily marshall/unmarshall my entities to reduce the amount of code needed to query the database.

As my entities are complex objects, meaning that an instance holds, for example, another class-type, or a array of them; I couldn't find any tutorials online to explain what I'm missing (maybe I'm not and that is how things need to be done) as the document-client makes me marshall them into the regular attribute-values structure which then makes the unmarshall into my entities not as simple as I would expect by their documentation...

Below is the function I've written (mostly copied) to get a client-connection to the database (it is maybe important to note that I'm working with DynamoDB local docker):

import { DynamoDBClient, DynamoDBClientConfig } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
import { NodeHttpHandler } from '@aws-sdk/node-http-handler';

const getClient = (): DynamoDBDocumentClient => {
    if (documentClient) {
        return documentClient;
    }

    const configuration = {} as DynamoDBClientConfig;
    configuration.region = 'localhost';
    configuration.credentials = {
        accessKeyId: 'accessKeyId',
        secretAccessKey: 'secretAccessKey',
    };
    configuration.requestHandler = new NodeHttpHandler({ connectionTimeout: 1000, socketTimeout: 1000 });
    configuration.maxAttempts = 2;
    configuration.endpoint = 'http://localhost:8000';

    client = new DynamoDBClient(configuration);

    const marshallOptions = {
        // Whether to automatically convert empty strings, blobs, and sets to `null`.
        convertEmptyValues: false, // false, by default.
        // Whether to remove undefined values while marshalling.
        removeUndefinedValues: true, // false, by default.
        // Whether to convert typeof object to map attribute.
        convertClassInstanceToMap: false, // false, by default. <-- HERE IS THE ISSUE
    };

    const unmarshallOptions = {
        // Whether to return numbers as a string instead of converting them to native JavaScript numbers.
        wrapNumbers: false, // false, by default.
    };

    const translateConfig = { marshallOptions, unmarshallOptions };

    documentClient = DynamoDBDocumentClient.from(client, translateConfig);

    return documentClient;
};

And here is an abstraction of the PutCommand for an instance of an entity of complex-type:

const createEntity = async (instance: ComplexEntityType): Promise<ComplexEntityType> => {
    const client = getClient();
    try {
        await client.send(
            new PutCommand({
                TableName: 'TableName',
                Item: {
                    PK: instance.pk,
                    SK: instance.sk,
                    instance,
                },
            }),
        );
    } catch (error) {
        console.log(error);
        throw error;
    }

    return instance;
};

When I try to save an entity of that complex-type I get the error:

Unsupported type passed: [object Object]. Pass options.convertClassInstanceToMap=true to marshall typeof object as map attribute.

Which, as you can see, makes me set the convertClassInstanceToMap in my client-configuration to true, which then makes the simple unmarshall into the complex-type not that simple (needs to go through the attribute-values).

So, am I missing something?

LioRz
  • 835
  • 1
  • 9
  • 17

0 Answers0