Skip to content
This repository has been archived by the owner on May 17, 2024. It is now read-only.

Commit

Permalink
Merge pull request #33 from zapier/pe-184--require-samples-for-non-hi…
Browse files Browse the repository at this point in the history
…dden-ops

PE-184  Require samples for non hidden ops
  • Loading branch information
ibolmo authored Mar 9, 2018
2 parents c73d58f + 13f5418 commit 51c709e
Show file tree
Hide file tree
Showing 13 changed files with 483 additions and 6 deletions.
7 changes: 4 additions & 3 deletions lib/functional-constraints/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
const checks = [
require('./searchOrCreateKeys'),
require('./deepNestedFields'),
require('./mutuallyExclusiveFields')
require('./mutuallyExclusiveFields'),
require('./requiredSamples')
];

const runFunctionalConstraints = definition => {
const runFunctionalConstraints = (definition, mainSchema) => {
return checks.reduce((errors, checkFunc) => {
const errorsForCheck = checkFunc(definition);
const errorsForCheck = checkFunc(definition, mainSchema);
if (errorsForCheck) {
errors = errors.concat(errorsForCheck);
}
Expand Down
56 changes: 56 additions & 0 deletions lib/functional-constraints/requiredSamples.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'use strict';

const _ = require('lodash');
const jsonschema = require('jsonschema');

// todo: deal with circular dep.
const RESOURCE_ID = '/ResourceSchema';
const RESOURCE_METHODS = ['get', 'hook', 'list', 'search', 'create'];

const check = definition => {
if (!definition.operation || _.get(definition, 'display.hidden')) {
return null;
}

const samples = _.get(definition, 'operation.sample', {});
return !_.isEmpty(samples)
? null
: new jsonschema.ValidationError(
'requires "sample", because it\'s not hidden',
definition,
definition.id
);
};

module.exports = (definition, mainSchema) => {
let definitions = [];

if (mainSchema.id === RESOURCE_ID) {
definitions = RESOURCE_METHODS.map(method => definition[method]).filter(
Boolean
);

// allow method definitions to inherit the sample
if (definition.sample) {
definitions.forEach(methodDefinition => {
if (methodDefinition.operation && !methodDefinition.operation.sample) {
methodDefinition.operation.sample = definition.sample;
}
});
}

if (!definitions.length) {
return [
new jsonschema.ValidationError(
'expected at least one resource operation',
definition,
definition.id
)
];
}
} else {
definitions = [definition];
}

return definitions.map(check).filter(Boolean);
};
4 changes: 2 additions & 2 deletions lib/schemas/BasicOperationSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module.exports = makeSchema(
description:
'Represents the fundamental mechanics of triggers, searches, or creates.',
type: 'object',
required: ['perform', 'sample'],
required: ['perform'],
properties: {
resource: {
description:
Expand All @@ -38,7 +38,7 @@ module.exports = makeSchema(
},
sample: {
description:
'What does a sample of data look like? Will use resource sample if missing.',
'What does a sample of data look like? Will use resource sample if missing. Required, if the display is not hidden.',
type: 'object',
// TODO: require id, ID, Id property?
minProperties: 1
Expand Down
24 changes: 24 additions & 0 deletions lib/schemas/CreateSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ module.exports = makeSchema(
sample: { id: 1 },
shouldLock: true
}
},
{
key: 'recipe',
noun: 'Recipe',
display: {
label: 'Create Recipe',
description: 'Creates a new recipe.',
hidden: true
},
operation: {
perform: '$func$2$f$'
}
}
],
antiExamples: [
Expand All @@ -46,6 +58,18 @@ module.exports = makeSchema(
description: 'Creates a new recipe.'
},
operation: { perform: '$func$2$f$', shouldLock: 'yes' }
},
{
key: 'recipe',
noun: 'Recipe',
display: {
label: 'Create Recipe',
description: 'Creates a new recipe.'
},
operation: {
perform: '$func$2$f$'
// sample is missing!
}
}
],
properties: {
Expand Down
35 changes: 35 additions & 0 deletions lib/schemas/ResourceMethodCreateSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,41 @@ module.exports = makeSchema(
'How will we find create a specific object given inputs? Will be turned into a create automatically.',
type: 'object',
required: ['display', 'operation'],
examples: [
{
display: {
label: 'Create Tag',
description: 'Create a new Tag in your account.'
},
operation: {
perform: '$func$2$f$',
sample: {
id: 1
}
}
},
{
display: {
label: 'Create Tag',
description: 'Create a new Tag in your account.',
hidden: true
},
operation: {
perform: '$func$2$f$'
}
}
],
antiExamples: [
{
display: {
label: 'Create Tag',
description: 'Create a new Tag in your account.'
},
operation: {
perform: '$func$2$f$'
}
}
],
properties: {
display: {
description: 'Define how this create method will be exposed in the UI.',
Expand Down
42 changes: 42 additions & 0 deletions lib/schemas/ResourceMethodGetSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,48 @@ module.exports = makeSchema(
'How will we get a single object given a unique identifier/id?',
type: 'object',
required: ['display', 'operation'],
examples: [
{
display: {
label: 'Get Tag by ID',
description: 'Grab a specific Tag by ID.'
},
operation: {
perform: {
url: '$func$0$f$'
},
sample: {
id: 385,
name: 'proactive enable ROI'
}
}
},
{
display: {
label: 'Get Tag by ID',
description: 'Grab a specific Tag by ID.',
hidden: true
},
operation: {
perform: {
url: '$func$0$f$'
}
}
}
],
antiExamples: [
{
display: {
label: 'Get Tag by ID',
description: 'Grab a specific Tag by ID.'
},
operation: {
perform: {
url: '$func$0$f$'
}
}
}
],
properties: {
display: {
description: 'Define how this get method will be exposed in the UI.',
Expand Down
39 changes: 39 additions & 0 deletions lib/schemas/ResourceMethodHookSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,45 @@ module.exports = makeSchema(
'How will we get notified of new objects? Will be turned into a trigger automatically.',
type: 'object',
required: ['display', 'operation'],
examples: [
{
display: {
label: 'Get Tag by ID',
description: 'Grab a specific Tag by ID.'
},
operation: {
type: 'hook',
perform: '$func$0$f$',
sample: {
id: 385,
name: 'proactive enable ROI'
}
}
},
{
display: {
label: 'Get Tag by ID',
description: 'Grab a specific Tag by ID.',
hidden: true
},
operation: {
type: 'hook',
perform: '$func$0$f$'
}
}
],
antiExamples: [
{
display: {
label: 'Get Tag by ID',
description: 'Grab a specific Tag by ID.'
},
operation: {
type: 'hook',
perform: '$func$0$f$'
}
}
],
properties: {
display: {
description:
Expand Down
44 changes: 44 additions & 0 deletions lib/schemas/ResourceMethodListSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,50 @@ module.exports = makeSchema(
'How will we get a list of new objects? Will be turned into a trigger automatically.',
type: 'object',
required: ['display', 'operation'],
examples: [
{
display: {
label: 'New User',
description: 'Trigger when a new User is created in your account.'
},
operation: {
perform: {
url: 'http://fake-crm.getsandbox.com/users'
},
sample: {
id: 49,
name: 'Veronica Kuhn',
email: 'veronica.kuhn@company.com'
}
}
},
{
display: {
label: 'New User',
description: 'Trigger when a new User is created in your account.',
hidden: true
},
operation: {
perform: {
url: 'http://fake-crm.getsandbox.com/users'
}
}
}
],
antiExamples: [
{
display: {
label: 'New User',
description: 'Trigger when a new User is created in your account.'
},
operation: {
perform: {
url: 'http://fake-crm.getsandbox.com/users'
}
// missing sample
}
}
],
properties: {
display: {
description:
Expand Down
35 changes: 35 additions & 0 deletions lib/schemas/ResourceMethodSearchSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,41 @@ module.exports = makeSchema(
'How will we find a specific object given filters or search terms? Will be turned into a search automatically.',
type: 'object',
required: ['display', 'operation'],
examples: [
{
display: {
label: 'Find a Recipe',
description: 'Search for recipe by cuisine style.'
},
operation: {
perform: '$func$2$f$',
sample: { id: 1 }
}
},
{
display: {
label: 'Find a Recipe',
description: 'Search for recipe by cuisine style.',
hidden: true
},
operation: {
perform: '$func$2$f$'
}
}
],
antiExamples: [
{
key: 'recipe',
noun: 'Recipe',
display: {
label: 'Find a Recipe',
description: 'Search for recipe by cuisine style.'
},
operation: {
perform: '$func$2$f$'
}
}
],
properties: {
display: {
description: 'Define how this search method will be exposed in the UI.',
Expand Down
Loading

0 comments on commit 51c709e

Please sign in to comment.