@politico/dynamo-records

v1.0.3
A utility library to simplify working with AWS DynamoDB records
dynamodb

@politico/dynamo-records

This library makes working with records in AWS DynamoDB simpler and more consistent. With a few key abstractions on top of the data being stored in the database, @politico/dynamo-records provides a powerful and consistent interface for working with your data in a NoSQL context.

Basic example

In a nontrivial application, the most common pattern is to create a records interface that you then use to create multiple record types. The commented file names below are just examples; you're free to structure your code however works best for your use case.

First, you create your records interface:

// in db.js
import { makeRecordsInterface } from '@politico/dynamo-records';

const db = makeRecordsInterface({
  table: 'MyTableName', // DynamoDB table that stores our records
  namespace: 'myservice', // a prefix to add to all hash keys
});

export default db;

Then, you use your records interface to construct multiple record types:

// in users.js
import { getUnknown } from '@politico/dynamo-records';
import db from './db';

const users = db.makeRecordType({
  type: 'user', // a string that uniquely identifies this record type
  getHashKey: ({ email }) => email,
  normalizeRecord: (doc) => {
    const email = getUnknown(doc, 'email');

    if (!email || typeof email !== 'string') {
      throw new Error('user must have an email');
    }

    return {
      email,
    };
  },
});

Another record example:

// in posts.js
import { getUnknown } from '@politico/dynamo-records';
import db from './db';

const posts = db.makeRecordType({
  type: 'post',
  getHashKey: ({ email }) => `posts:${email}`,
  getRangeKey: ({ timestamp }) => timestamp,
  normalizeRecord: (doc) => {
    const email = getUnknown(doc, 'email');
    const timestamp = getUnknown(doc, 'timestamp');
    const text = getUnknown(doc, 'text', '');

    if (!email || typeof email !== 'string') {
      throw new Error('post must have an author email');
    }

    if (!timestamp || typeof timestamp !== 'string') {
      throw new Error('post must have a timestamp');
    }

    if (typeof text !== 'string') {
      throw new Error('post text must be a string');
    }

    return {
      email,
      timestamp,
      text,
    };
  },
});

Once you have your record types defined, you can use them to interact with your stored data:

// in index.js
import users from './users';
import posts from './posts';

const doSomething = async () => {
  const email = '[email protected]';

  // retrieve a single record
  const someUser = await users.getRecord({ email });

  // query paginated records
  const userPosts = await posts.queryRecords({
    hash: { email }, // corresponds to input of posts.getHashKey()
    direction: 'backwards',
  });

  // add a record to the db
  await posts.putRecord({
    email,
    timestamp: new Date().toISOString(),
    text: 'Hello world!',
  });
};

Check out the docs for a more complete introduction.

npm i @politico/dynamo-records

Metadata

  • ISC
  • Whatever
  • Andrew Milligan
  • released 1/1/2024

Downloads