Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

strict mode: unknown keyword: "format" #50

Open
bestickley opened this issue Jan 5, 2022 · 5 comments
Open

strict mode: unknown keyword: "format" #50

bestickley opened this issue Jan 5, 2022 · 5 comments

Comments

@bestickley
Copy link

Hello, I'm using ajv@8.8.2 and ajv-formats@2.1.1 in an AWS Lambda (Node.js 14) and I'm getting this error:

{
    "errorType": "Error",
    "errorMessage": "strict mode: unknown keyword: \"format\"",
    "stack": [
        "Error: strict mode: unknown keyword: \"format\"",
        "    at null.Gq (/node_modules/.pnpm/ajv@8.8.2/node_modules/ajv/lib/compile/util.ts:211:28)",
        "    at null.$q (/node_modules/.pnpm/ajv@8.8.2/node_modules/ajv/lib/compile/util.ts:27:22)",
        "    at null.Wfe (/node_modules/.pnpm/ajv@8.8.2/node_modules/ajv/lib/compile/util.ts:17:3)",
        "    at Object.code (/node_modules/.pnpm/ajv@8.8.2/node_modules/ajv/lib/vocabularies/jtd/metadata.ts:11:9)",
        "    at null.UN (/node_modules/.pnpm/ajv@8.8.2/node_modules/ajv/lib/compile/validate/index.ts:523:9)",
        "    at null.<anonymous> (/node_modules/.pnpm/ajv@8.8.2/node_modules/ajv/lib/compile/validate/index.ts:265:9)",
        "    at Nq.code (/node_modules/.pnpm/ajv@8.8.2/node_modules/ajv/lib/compile/codegen/index.ts:525:33)",
        "    at Nq.block (/node_modules/.pnpm/ajv@8.8.2/node_modules/ajv/lib/compile/codegen/index.ts:680:20)",
        "    at null.RN (/node_modules/.pnpm/ajv@8.8.2/node_modules/ajv/lib/compile/validate/index.ts:262:7)",
        "    at null.v (/node_modules/.pnpm/ajv@8.8.2/node_modules/ajv/lib/compile/validate/index.ts:248:7)"
    ]
}

Here is the function:

import {
  CognitoIdentityProviderClient,
  AdminCreateUserCommand,
  AdminAddUserToGroupCommand,
} from "@aws-sdk/client-cognito-identity-provider";
import { AppSyncResolverEvent } from "aws-lambda";
import Ajv, { JTDDataType } from "ajv/dist/jtd";
import format from "ajv/dist/vocabularies/format/format";
import addFormats from "ajv-formats";
import { transformUser } from "./user";
import { groupNames } from "./group";

// validation
const ajv = new Ajv();
ajv.addKeyword(format);
addFormats(ajv, ["email"]);
const schema = {
  properties: {
    email: { type: "string", metadata: { format: "email" } },
    family_name: { type: "string" },
    given_name: { type: "string" },
    groups: {
      elements: { enum: groupNames },
    },
    username: { type: "string" },
  },
} as const;
const validate = ajv.compile(schema);

// params
interface CreateUserGqlArgs {
  input: JTDDataType<typeof schema>;
}
interface CreateUserParams {
  cognitoClient: CognitoIdentityProviderClient;
  event: AppSyncResolverEvent<CreateUserGqlArgs>;
  userPoolId: string;
}

export async function createUser(props: CreateUserParams): Promise<unknown> {
  const { cognitoClient, event, userPoolId } = props;
  if (!validate(event.arguments.input)) {
    throw new Error(validate.errors?.toString());
  }
  const { username, groups, ...inputUserAttributes } = event.arguments.input;
  const userAttributes = Object.entries(inputUserAttributes).map(([k, v]) => ({
    Name: k,
    Value: v,
  }));
  const res = await cognitoClient.send(
    new AdminCreateUserCommand({
      UserPoolId: userPoolId,
      Username: username,
      UserAttributes: userAttributes,
    })
  );
  await Promise.all(
    groups.map((g) =>
      cognitoClient.send(
        new AdminAddUserToGroupCommand({
          GroupName: g,
          Username: username,
          UserPoolId: userPoolId,
        })
      )
    )
  );
  if (!res.User) throw new Error("Error while creating user");
  const user = transformUser(res.User);
  return user;
}

Does anyone know what's going on? Thank you!

@bestickley
Copy link
Author

@riker09, do you have insight? I based my code off your example here

@riker09
Copy link

riker09 commented Jan 13, 2022

Sorry, I'm afraid I will not be able to help you. I'm just a consumer of this library as well and have moved on to another project in the meantime.

Your code seems correct to me, though. So maybe it is something with the version?

@epoberezkin
Copy link
Member

epoberezkin commented Jan 15, 2022

@bestickley I believe you could just put "format" inside "metadata" member - JTD only allows extensions in this way, as they are no-op in this way.

If this does not work, please put pure JavaScript example in runkit so I can investigate.

Edit: ignore that, it's already inside... not sure, it does look correct. Please make a runnable example in runkit. Could be a version problem indeed...

@bestickley
Copy link
Author

@riker09, no problem.
@epoberezkin, thank you for your response. Here is the runkit example: https://runkit.com/bestickley/61eb0e06ce01ed0008bacdfe

@offlinehacker
Copy link

ajv-formats does not seem to be supported by ajv-jtd, only ajv-keywords, also ajv-formats is not mentioned in docs (https://ajv.js.org/json-type-definition.html#extending-jtd)

Also according to docs: While it is ok to put some human readable information in metadata member, it is recommended not to add any validation logic there (even if it is supported by Ajv).

I decided to add regexp keyword from ajv-keywords, since I don't need anything else additionally to what jtd already supports.

import Ajv from "ajv/dist/jtd";
import addKeyword from "ajv-keywords";

export const ajv = new Ajv({
  parseDate: true,
});

ajv.addKeyword("description");
addKeyword(ajv, ["regexp"]);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants