I recently wrote a util function, that creates lam...
# sst
g
I recently wrote a util function, that creates lambdas in a directory. The logic shown below
Copy code
import fs from 'fs';
import path from 'path';
import { Stack, Function, FunctionProps } from '@serverless-stack/resources';
import { getPathConstruct } from './formatting';

const INITIAL_RECORDS: LambdaRecords = {};
/**
 * Creates functions for all files in the provided directory
 *
 * @param stack - The stack in which the functions belong to
 * @param directory - The directory where the functions should be created from
 * @param props - Common handler props that you need to pass down to your functions
 *
 * @returns A record of the lambda functions with the keys as the PascalCase version of the filename
 */
export function getPathFunctions(
  stack: Stack,
  directory: string,
  props: LambdaProps = {},
) {
  const { stage } = stack;
  const root = process.cwd();
  const dir = directory.replace(`${root}/`, '');
  const functions = fs.readdirSync(directory);

  return functions.reduce((memo, filename) => {
    const fullPath = path.resolve(directory, filename);
    const stats = fs.statSync(fullPath);
    if (stats.isDirectory()) {
      return memo;
    }
    const [name] = filename.split('.');
    const constructName = getPathConstruct(filename);
    const functionName = `${stage}-${name}`;
    const id = `${constructName}Lambda`;
    const handler = `${dir}/${name}.handler`;
    const lambdaFunction = new Function(stack, id, {
      handler,
      functionName,
      ...props,
    });

    return {
      ...memo,
      [constructName]: lambdaFunction,
    };
  }, INITIAL_RECORDS);
}

type LambdaProps = Omit<Omit<FunctionProps, 'handler'>, 'functionName'>

export type LambdaRecords = Record<string, Function>;
Do you guys think this would be a valuable thing to add? We could add a static method on the Function class like
Function.fromDirectory(...)
obviously we would have to make the functionality more generic.
f
This is pretty interesting! Are you trying to Currently you can set the default function props on the `App`:
Copy code
app.setDefaultFunctionProps({
  runtime: ...,
  environment: { ... },
});
And you can create a function by just supplying the handler path, ie:
Copy code
routes: {
  "Get /users": "src/list_users.main",
  "POST /users": "src/create_user.main",
}
What are benefiting from this script?
n
We didn’t like defining the routes as strings because it’s more error prone boilerplate. We added an abstraction that loops through an object of methods and creates the route strings for us.
So +1 for any implementation that makes defining routes and methods more type safe out of the box.
f
Hey @Nick Laffey, can you share a snippet example?
g
There are 2 benefits 1. I can structure a group of lambdas in a directory that I want to use for a particular stack 2. And the names of my lambda don't have that funny id at the end, but that one can be added in pretty easily if that's what you are aiming for.
Copy code
const LAMBDA_ROOT = path.resolve(ROOT, 'src/api');
... // My Api Stack had this 
 const api = getPathFunctions(this, LAMBDA_ROOT, {
  environment,
  timeout: Duration.seconds(29),
  bundle: {
    nodeModules: ['knex'],
  },
 });
const { CreateUser, GetAuthFlow, Graphql } = api;
    const domainName = `${prefix}<http://api.crownrescue.com|api.crownrescue.com>`;

    this.handler = Graphql;
    new SSTApi(this, 'Api', {
      routes: {
        'ANY /graphql': {
          authorizationType: ApiAuthorizationType.JWT,
          function: Graphql,
          authorizer: new HttpUserPoolAuthorizer({
            authorizerName: 'UserPoolAuthorizer',
            userPool,
            userPoolClient,
            userPoolRegion: region,
          }),
        },
        'POST /auth': {
          function: GetAuthFlow,
        },
        'POST /create-user': {
          function: CreateUser,
        },
      },
      customDomain: {
        domainName,
        hostedZone: '...',
      },
    });
...
and my Cognito Stack has this
Copy code
const TRIGGERS_ROOT = path.resolve(ROOT, 'src/triggers');
const triggers = getPathFunctions(this, TRIGGERS_ROOT, {
  timeout: Duration.seconds(29),
});
const {
  PreSignUp,
  CreateAuthChallenge,
  DefineAuthChallenge,
  VerifyAuthChallengeResponse,
} = triggers;
@Frank Let me know if that makes sense
n
@Frank Our current implementation is a little harder to share but when I was first exploring the idea here’s what we had: https://gist.github.com/nlaffey-icario/43aafbf4d2a9a6e0aff415a826a2ce63
Now that I’m looking at this again there’s still string methods in there 😞. Hah so maybe disregard… might be interesting to see still though.
g
@Nick Laffey Yeah, I don't think we were trying to solve the same issue.
n
Nope, sorry for muddying the waters 🙂
g
No worries @Nick Laffey
f
@Nick Laffey ah I see.. programmatically building the routes
n
Yeah felt like some kind of abstraction was needed. Like I said we’re doing it a different way now that I think is better but it’s more difficult to share.
f
@Jay take a look at this thread and let’s do a call about this.