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?