Skip to content

JavaScript code example standards

Corey Pyle edited this page Jul 29, 2024 · 12 revisions

JavaScript Standards

Directory structure

  • javascriptv3 is considered the project root.
  • All examples exist under example_code.
  • Each directory under example_code corresponds to an AWS service.
  • Directory names should be lowercase with underscores.
  • File names should be lowercase with dashes.
  • cross-services is a special directory for examples that use multiple services.
  • A service directory typically has the following structure:
    • actions/
        {action-name}.js
      scenarios/
        web/
          {web-scenario-name}/
        {scenario-name}.js
        {scenario_folder}/
          {scenario-file}.js
      tests/
        {integ-test-name}.integration.test.js
        {unit-test-name}.unit.test.js
      package.json
      README.md
      vite.config.js
      

Make a file runnable

When an file needs to be run from the command line, add the following code to the bottom. This ensures the file can be run directly, or imported.

// Call function if run directly
import { fileURLToPath } from "url";
if (process.argv[1] === fileURLToPath(import.meta.url)) {
  example();
}

Use the modularized style and ES6 imports

Previous versions of the AWS SDK for JavaScript were less modularized. The latest versions rely heavily on modular packages. Import only the clients and commands needed.

import { ListBucketsCommand, S3Client } from "@aws-sdk/client-s3";

const client = new S3Client({});

export const helloS3 = async () => {
  const command = new ListBucketsCommand({});

  const { Buckets } = await client.send(command);
  console.log("Buckets: ");
  console.log(Buckets.map((bucket) => bucket.Name).join("\n"));
  return Buckets;
};

Focus on education over engineering

While it's tempting to abstract things like client instantiation, it's more educational to show such things in close proximity. Over abstraction makes it harder for a customer to understand what's happening.

const createFunction = async (funcName, roleArn) => {
  const client = new LambdaClient({});
  const code = await readFile(`${dirname}../functions/${funcName}.zip`);

  const command = new CreateFunctionCommand({
    Code: { ZipFile: code },
    FunctionName: funcName,
    Role: roleArn,
    Architectures: [Architecture.arm64],
    Handler: "index.handler", // Required when sending a .zip file
    PackageType: PackageType.Zip, // Required when sending a .zip file
    Runtime: Runtime.nodejs16x, // Required when sending a .zip file
  });

  return client.send(command);
};

Use the provided Scenario framework when necessary

Some examples are more complicated than just singular client calls. In cases like these, there should be a balance between education and engineering. javascriptv3/example_code/libs/scenario is a module that provides a framework for setting up more complex examples. Use this framework when an example is more than a few steps.

For guidance on using the scenario framework, see javascriptv3/example_code/libs/scenario/scenario-example.js.

Prefer snippet files when possible

If an example is contained within one file, use snippet_files in the metadata instead of snippet_tags.

Create with integration tests in mind

Unit tests are nice. Integration tests are required. The goal of the integration testing is to ensure our examples are fresh and haven't suffered breaking changes from the services.

Adhere to the following principles when creating integration tests:

  • Ensure proper setup an tear down. Any resources created for the test should be deleted by the test.
  • At minimum, ensure example code does not error.

Leave things cleaner than you found them

If you modify an example, refactor it to match these standards.

Clone this wiki locally