jsonapi-server
Advanced tools
Comparing version 2.1.0 to 2.2.0
@@ -0,1 +1,5 @@ | ||
- 2016-11-07 - v2.2.0 | ||
- 2016-11-07 - Adding polymorphic relationships | ||
- 2016-11-07 - Correctly handle validation errors when including non-existant resources | ||
- 2016-11-07 - Added Array Joi type for GraphQL | ||
- 2016-09-29 - v2.1.0 | ||
@@ -2,0 +6,0 @@ - 2016-09-29 - Enable injection of an Express Router |
@@ -27,2 +27,4 @@ const jsonApi = require('../../.') | ||
.example(false), | ||
tags: jsonApi.Joi.array().items(jsonApi.Joi.string()) | ||
.description('Tags for the photo'), | ||
photographer: jsonApi.Joi.one('people') | ||
@@ -44,2 +46,3 @@ .description('The person who took the photo'), | ||
raw: true, | ||
tags: ['neo', 'morpheus'], | ||
photographer: { type: 'people', id: 'ad3aa89e-9c5b-4ac9-a652-6670f9f27587' } | ||
@@ -54,2 +57,3 @@ }, | ||
width: 60, | ||
tags: ['galapagos', 'emperor'], | ||
photographer: { type: 'people', id: 'd850ea75-4427-4f81-8595-039990aeede5' } | ||
@@ -64,2 +68,3 @@ }, | ||
width: 350, | ||
tags: ['black', 'green'], | ||
photographer: { type: 'people', id: 'ad3aa89e-9c5b-4ac9-a652-6670f9f27587' } | ||
@@ -66,0 +71,0 @@ } |
@@ -5,2 +5,3 @@ 'use strict' | ||
const graphQl = require('graphql') | ||
const readTypes = require('./readTypes.js') | ||
@@ -20,2 +21,16 @@ joiConverter.simpleAttribute = joiScheme => { | ||
if (type === 'array') { | ||
if (joiScheme._inner.items.length === 1) { | ||
let joinSubType = joiConverter.simpleAttribute(joiScheme._inner.items[0]) | ||
if (!joinSubType) { | ||
throw new Error('Unable to parse Joi type, got ' + JSON.stringify(joiScheme)) | ||
} | ||
return new graphQl.GraphQLList(graphQl.GraphQLString) | ||
} else { | ||
throw new Error('Joi arrays must contain a single type') | ||
} | ||
} | ||
const uType = type[0].toUpperCase() + type.substring(1) | ||
@@ -35,3 +50,4 @@ type = graphQl[`GraphQL${uType}`] | ||
} else { | ||
const otherType = joiScheme._settings.__one || joiScheme._settings.__many | ||
let otherType = joiScheme._settings.__one || joiScheme._settings.__many | ||
otherType = otherType.join(readTypes.UNION_JOIN_CONST) | ||
type = graphQlResources[otherType] | ||
@@ -38,0 +54,0 @@ |
@@ -8,12 +8,18 @@ 'use strict' | ||
const filterArgs = require('./filterArgs.js') | ||
const UNION_JOIN_CONST = '_PluS_' | ||
readTypes.UNION_JOIN_CONST = UNION_JOIN_CONST | ||
readTypes.generate = allResourceConfig => { | ||
const allReadTypes = { } | ||
const allUnionTypes = [ ] | ||
Object.keys(allResourceConfig).forEach(resource => { | ||
allReadTypes[resource] = readTypes.createReadType(allResourceConfig[resource], allReadTypes) | ||
allReadTypes[resource] = readTypes.createReadType(allResourceConfig[resource], allReadTypes, allUnionTypes) | ||
}) | ||
allUnionTypes.forEach(unionType => { | ||
allReadTypes[unionType] = readTypes.createUnionType(unionType, allReadTypes) | ||
}) | ||
return allReadTypes | ||
} | ||
readTypes.createReadType = (resourceConfig, otherTypes) => { | ||
readTypes.createReadType = (resourceConfig, otherTypes, allUnionTypes) => { | ||
const someType = { | ||
@@ -42,3 +48,5 @@ name: resourceConfig.resource, | ||
const otherResource = joiScheme._settings.__one || joiScheme._settings.__many | ||
fields[attribute].args = filterArgs.generate(otherResource) | ||
if (otherResource.length === 1) { | ||
fields[attribute].args = filterArgs.generate(otherResource) | ||
} | ||
} | ||
@@ -50,3 +58,24 @@ }) | ||
Object.keys(resourceConfig.attributes).forEach(attribute => { | ||
const joiScheme = resourceConfig.attributes[attribute] | ||
if (!joiScheme._settings) return | ||
const otherResource = joiScheme._settings.__one || joiScheme._settings.__many | ||
if (otherResource.length <= 1) return | ||
const unionType = otherResource.join(UNION_JOIN_CONST) | ||
if (allUnionTypes.indexOf(unionType) !== -1) return | ||
allUnionTypes.push(unionType) | ||
}) | ||
return new graphQl.GraphQLObjectType(someType) | ||
} | ||
readTypes.createUnionType = (unionType, allReadTypes) => { | ||
let graphQlTypes = unionType.split(UNION_JOIN_CONST).map(a => allReadTypes[a]) | ||
return new graphQl.GraphQLUnionType({ | ||
name: unionType, | ||
types: graphQlTypes, | ||
resolveType: function (value) { | ||
return graphQlTypes[unionType.split(UNION_JOIN_CONST).indexOf(value.type)] | ||
} | ||
}) | ||
} |
@@ -87,3 +87,3 @@ 'use strict' | ||
[].concat(data.relationships[attribute].data).forEach(relation => { | ||
relation.type = joiSchema._settings.__one || joiSchema._settings.__many | ||
relation.type = (joiSchema._settings.__one || joiSchema._settings.__many)[0] | ||
}) | ||
@@ -99,3 +99,3 @@ } | ||
const combined = [].concat.apply([], arrays) | ||
let fields = combined.map(thing => thing.name.value) | ||
let fields = combined.map(thing => (thing.name || { }).value).filter(a => a) | ||
fields = fields.join(',') | ||
@@ -102,0 +102,0 @@ return fields |
@@ -14,18 +14,23 @@ 'use strict' | ||
} | ||
Joi.one = resource => { | ||
if (typeof resource !== 'string') throw new Error('Expected a string when defining a primary relation via .one()') | ||
const obj = Joi.alternatives().try( | ||
Joi.any().valid(null), // null | ||
ourJoi._joiBase(resource) | ||
) | ||
Joi.one = function () { | ||
const resources = Array.prototype.slice.call(arguments) | ||
resources.forEach(resource => { | ||
if (typeof resource !== 'string') throw new Error('Expected a string when defining a primary relation via .one()') | ||
}) | ||
const obj = Joi.alternatives().try([ | ||
Joi.any().valid(null) // null | ||
].concat(resources.map(ourJoi._joiBase))) | ||
obj._settings = { | ||
__one: resource | ||
__one: resources | ||
} | ||
return obj | ||
} | ||
Joi.many = resource => { | ||
if (typeof resource !== 'string') throw new Error('Expected a string when defining a primary relation via .many()') | ||
const obj = Joi.array().items(ourJoi._joiBase(resource)) | ||
Joi.many = function () { | ||
const resources = Array.prototype.slice.call(arguments) | ||
resources.forEach(resource => { | ||
if (typeof resource !== 'string') throw new Error('Expected a string when defining a primary relation via .one()') | ||
}) | ||
const obj = Joi.array().items(resources.map(ourJoi._joiBase)) | ||
obj._settings = { | ||
__many: resource | ||
__many: resources | ||
} | ||
@@ -45,3 +50,3 @@ return obj | ||
obj._settings = { | ||
__one: config.resource, | ||
__one: [ config.resource ], | ||
__as: config.as | ||
@@ -55,3 +60,3 @@ } | ||
obj._settings = { | ||
__many: config.resource, | ||
__many: [ config.resource ], | ||
__as: config.as | ||
@@ -58,0 +63,0 @@ } |
@@ -39,5 +39,6 @@ 'use strict' | ||
includePP._arrayToTree = (request, includes, filters, callback) => { | ||
const validationErrors = [ ] | ||
const tree = { | ||
_dataItems: null, | ||
_resourceConfig: request.resourceConfig | ||
_resourceConfig: [ ].concat(request.resourceConfig) | ||
} | ||
@@ -51,5 +52,7 @@ | ||
let resourceAttribute = node._resourceConfig.attributes[first] | ||
let resourceAttribute = node._resourceConfig.map(resourceConfig => { | ||
return resourceConfig.attributes[first] | ||
}).filter(a => a).pop() | ||
if (!resourceAttribute) { | ||
return callback({ | ||
return validationErrors.push({ | ||
status: '403', | ||
@@ -63,3 +66,3 @@ code: 'EFORBIDDEN', | ||
if (!resourceAttribute) { | ||
return callback({ | ||
return validationErrors.push({ | ||
status: '403', | ||
@@ -80,3 +83,3 @@ code: 'EFORBIDDEN', | ||
_dataItems: [ ], | ||
_resourceConfig: jsonApi._resources[resourceAttribute], | ||
_resourceConfig: resourceAttribute.map(a => jsonApi._resources[a]), | ||
_filter: [ ] | ||
@@ -98,2 +101,3 @@ } | ||
if (validationErrors.length > 0) return callback(validationErrors) | ||
return callback(null, tree) | ||
@@ -100,0 +104,0 @@ } |
@@ -130,3 +130,3 @@ 'use strict' | ||
if (schemaProperty._settings.__as) { | ||
const relatedResource = schemaProperty._settings.__one || schemaProperty._settings.__many | ||
const relatedResource = (schemaProperty._settings.__one || schemaProperty._settings.__many)[0] | ||
// get information about the linkage - list of ids and types | ||
@@ -133,0 +133,0 @@ // /rest/bookings/relationships/?customer=26aa8a92-2845-4e40-999f-1fa006ec8c63 |
@@ -57,3 +57,5 @@ 'use strict' | ||
} | ||
request.resourceConfig = jsonApi._resources[relation._settings.__one || relation._settings.__many] | ||
request.resourceConfig = (relation._settings.__one || relation._settings.__many).map(resourceName => { | ||
return jsonApi._resources[resourceName] | ||
}) | ||
response = responseHelper._generateResponse(request, resourceConfig, relatedResources) | ||
@@ -60,0 +62,0 @@ if (relatedResources !== null) { |
@@ -46,3 +46,3 @@ 'use strict' | ||
for (let i = 0; i < theirs.length; i++) { | ||
if (theirs[i].type !== relationType) { | ||
if (relationType.indexOf(theirs[i].type) === -1) { | ||
return callback({ | ||
@@ -49,0 +49,0 @@ status: '403', |
@@ -29,7 +29,7 @@ 'use strict' | ||
if (!relation || relation.__as) return false | ||
relation = relation.__many || relation.__one | ||
relation = (relation.__many || relation.__one)[0] | ||
return (jsonApi._resources[relation] && jsonApi._resources[relation].handlers.find) | ||
}).forEach(relationName => { | ||
let relation = resourceConfig.attributes[relationName] | ||
relation = relation._settings.__one || relation._settings.__many | ||
relation = (relation._settings.__one || relation._settings.__many)[0] | ||
@@ -36,0 +36,0 @@ swaggerPaths._addDeepPaths(paths, resourceName, resourceConfig, relationName, relation) |
{ | ||
"name": "jsonapi-server", | ||
"version": "2.1.0", | ||
"version": "2.2.0", | ||
"description": "A config driven NodeJS framework implementing json:api", | ||
@@ -26,2 +26,3 @@ "keywords": [ | ||
"debug": "^2.2.0", | ||
"eslint-plugin-promise": "^3.3.0", | ||
"express": "^4.13.4", | ||
@@ -28,0 +29,0 @@ "express-graphql": "^0.5.4", |
@@ -656,2 +656,18 @@ const assert = require('assert') | ||
}) | ||
it('should give clean validation errors', done => { | ||
const url = 'http://localhost:16006/rest/articles?include=fdfdds,sdf' | ||
helpers.request({ | ||
method: 'GET', | ||
url | ||
}, (err, res, json) => { | ||
assert.equal(err, null) | ||
json = helpers.validateError(json) | ||
assert.equal(res.statusCode, '403', 'Expecting 403 EFORBIDDEN') | ||
assert.equal(json.errors.length, 2, 'Should be 2 errors') | ||
done() | ||
}) | ||
}) | ||
}) | ||
@@ -658,0 +674,0 @@ }) |
@@ -10,3 +10,2 @@ const assert = require('assert') | ||
describe('Testing jsonapi-server graphql', () => { | ||
@@ -19,2 +18,3 @@ describe('read operations', () => { | ||
width | ||
tags | ||
photographer(firstname: "Rahul") { | ||
@@ -31,2 +31,3 @@ firstname | ||
'width': 60, | ||
'tags': ['galapagos', 'emperor'], | ||
'photographer': null | ||
@@ -37,2 +38,3 @@ }, | ||
'width': 350, | ||
'tags': ['black', 'green'], | ||
'photographer': { | ||
@@ -39,0 +41,0 @@ 'firstname': 'Rahul' |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
275151
98
6505
19
+ Addedeslint-plugin-promise@^3.3.0
+ Addedeslint-plugin-promise@3.8.0(transitive)