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

[RND-651] Ability to loosely allow overposted material for parity #314

Merged
merged 12 commits into from
Nov 13, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export type QueryStringValidationResult = {
* Validates that those queryParameters which are present are actually fields on the API resource
*/
export function validateQueryParameters(resourceSchema: ResourceSchema, queryParameters: FrontendQueryParameters): string[] {
const { queryValidator } = getSchemaValidatorsFor(resourceSchema);
const { queryValidator } = getSchemaValidatorsFor(resourceSchema, true);

let errors: string[] = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ export type ResourceSchemaValidators = {
updateValidator: ValidateFunction;
};

function initializeAjv(): Ajv {
const removeAdditional = false; // TODO: replace on merge with RND-651
function initializeAjv(isQueryParameterValidator: boolean): Ajv {
// A query parameter validator cannot have additional properties
const removeAdditional = isQueryParameterValidator ? false : getBooleanFromEnvironment('ALLOW_OVERPOSTING', false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly, the ODS/API does not reject spurious query string values. However, I agree with the approach here in Meadowlark. We should let people know that their query string was invalid.

const coerceTypes = getBooleanFromEnvironment('ALLOW_TYPE_COERCION', false);

const ajv = new Ajv({ allErrors: true, coerceTypes, removeAdditional });
Expand All @@ -34,16 +35,19 @@ let ajv: Ajv | null = null;
// simple cache implementation, see: https://rewind.io/blog/simple-caching-in-aws-lambda-functions/
/** This is a cache mapping ResourceSchema objects to compiled ajv JSON Schema validators for the API resource */
const validatorCache: Map<ResourceSchema, ResourceSchemaValidators> = new Map();
const queryValidatorCache: Map<ResourceSchema, ResourceSchemaValidators> = new Map();

/**
* Returns the API resource JSON Schema validator functions for the given ResourceSchema. Caches results.
*/
export function getSchemaValidatorsFor(resourceSchema: ResourceSchema): ResourceSchemaValidators {
if (ajv == null) ajv = initializeAjv();

const cachedValidators: ResourceSchemaValidators | undefined = validatorCache.get(resourceSchema);
export function getSchemaValidatorsFor(
resourceSchema: ResourceSchema,
isQueryParameterValidator: boolean = false,
): ResourceSchemaValidators {
const validatorCacheObject = isQueryParameterValidator ? queryValidatorCache : validatorCache;
const cachedValidators: ResourceSchemaValidators | undefined = validatorCacheObject.get(resourceSchema);
if (cachedValidators != null) return cachedValidators;

ajv = initializeAjv(isQueryParameterValidator);
const resourceValidators: ResourceSchemaValidators = {
insertValidator: ajv.compile(resourceSchema.jsonSchemaForInsert),
queryValidator: ajv.compile(resourceSchema.jsonSchemaForQuery),
Expand All @@ -58,4 +62,5 @@ export function getSchemaValidatorsFor(resourceSchema: ResourceSchema): Resource
*/
export function clearAllValidatorCache(): void {
validatorCache.clear();
queryValidatorCache.clear();
}
4 changes: 4 additions & 0 deletions Meadowlark-js/packages/meadowlark-core/test/TestHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ export function apiSchemaFrom(metaEd: MetaEdEnvironment): ApiSchema {
const pluginEnvironment = metaEd.plugin.get('edfiApiSchema') as PluginEnvironment;
return (pluginEnvironment.data as PluginEnvironmentEdfiApiSchema).apiSchema;
}

export function restoreSpies(spies: jest.SpyInstance[]) {
spies.forEach((spy) => spy.mockRestore());
}
Loading
Loading