Skip to content

Commit

Permalink
Resolves devour-js#263 added a means to disable attaching relationshi…
Browse files Browse the repository at this point in the history
…p metadata on unresolved includes
  • Loading branch information
ibustosatlegalzoom committed Jul 18, 2024
1 parent 0ffa3df commit 605ba54
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 7 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ let { data, errors, meta, links } = jsonApi.findAll('post', {include: 'comments'
// => data.comment will be populated with any comments included by your API
```

By default, Devour will include relationship metadata (id, type, and other metadata) in each response. It may be handy to exclude this metadata from the response when the relationship is not resolved by the backend (not listed in the "includes" Json:api response). For this, make sure the `attachRelationshipDataOnUnresolvedIncludes` client flag is set to `false`, (default value is `true`).

### Flexibility

Devour uses a fully middleware based approach. This allows you to easily manipulate any part of the request and response cycle by injecting your own middleware. In fact, it's entirely possible to fully remove our default middleware and write your own. Moving forward we hope to see adapters for different server implementations. If you'd like to take a closer look at the middleware layer, please checkout:
Expand Down
4 changes: 3 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ class JsonApi {
auth: {},
bearer: null,
trailingSlash: { collection: false, resource: false },
disableErrorsForMissingResourceDefinitions: false
disableErrorsForMissingResourceDefinitions: false,
attachRelationshipDataOnUnresolvedIncludes: true
}

const deprecatedConstructors = (args) => {
Expand All @@ -95,6 +96,7 @@ class JsonApi {
this.apiUrl = options.apiUrl
this.bearer = options.bearer
this.disableErrorsForMissingResourceDefinitions = options.disableErrorsForMissingResourceDefinitions
this.attachRelationshipDataOnUnresolvedIncludes = options.attachRelationshipDataOnUnresolvedIncludes
this.models = {}
this.deserialize = deserialize
this.serialize = serialize
Expand Down
17 changes: 11 additions & 6 deletions src/middleware/json-api/_deserialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,13 @@ function attachHasOneFor (model, attribute, item, included, key) {
return resource.call(this, relatedItems[0], included, true)
}

const relationshipData = _get(item.relationships, [key, 'data'], false)
if (relationshipData) {
return relationshipData
if (this.attachRelationshipDataOnUnresolvedIncludes) {
const relationshipData = _get(item.relationships, [key, 'data'], false)
if (relationshipData) {
return relationshipData
}
}

return null
}

Expand All @@ -137,9 +140,11 @@ function attachHasManyFor (model, attribute, item, included, key) {
return collection.call(this, relatedItems, included, true)
}

const relationshipData = _get(item.relationships, [key, 'data'], false)
if (relationshipData) {
return relationshipData
if (this.attachRelationshipDataOnUnresolvedIncludes) {
const relationshipData = _get(item.relationships, [key, 'data'], false)
if (relationshipData) {
return relationshipData
}
}

return []
Expand Down
77 changes: 77 additions & 0 deletions test/api/deserialize-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,4 +426,81 @@ describe('deserialize', () => {
expect(product.tags[1].id).to.eql('6')
expect(product.tags[1].type).to.eql('tags')
})

it('should not include relationship data on unresolved hasMany relationships if attachRelationshipDataOnUnresolvedIncludes flag is set to false', () => {
jsonApi = new JsonApi({
apiUrl: 'http://myapi.com',
attachRelationshipDataOnUnresolvedIncludes: false
})
jsonApi.define('product', {
title: '',
tags: {
jsonApi: 'hasMany',
type: 'tag'
}
})
jsonApi.define('tag', {
name: ''
})
const mockResponse = {
data: {
id: '1',
type: 'products',
attributes: {
title: 'hello'
},
relationships: {
tags: {
data: [
{ id: '5', type: 'tags' },
{ id: '6', type: 'tags' }
]
}
}
}
}
const product = deserialize.resource.call(jsonApi, mockResponse.data, mockResponse.included)
expect(product.id).to.eql('1')
expect(product.type).to.eql('products')
expect(product.title).to.eql('hello')
expect(product.tags).to.be.an('array')
expect(product.tags).to.be.empty()
})

it('should not include relationship data on unresolved hasOne relationships if attachRelationshipDataOnUnresolvedIncludes flag is set to false', () => {
jsonApi = new JsonApi({
apiUrl: 'http://myapi.com',
attachRelationshipDataOnUnresolvedIncludes: false
})
jsonApi.define('product', {
title: '',
tag: {
jsonApi: 'hasOne',
type: 'tag'
}
})
jsonApi.define('tag', {
name: ''
})
const mockResponse = {
data: {
id: '1',
type: 'products',
attributes: {
title: 'hello'
},
relationships: {
tag: {
data: { id: '5', type: 'tag' }
}
}
}
}
const product = deserialize.resource.call(jsonApi, mockResponse.data, mockResponse.included)
expect(product.id).to.eql('1')
expect(product.type).to.eql('products')
expect(product.title).to.eql('hello')
expect(product.tag).to.not.be.an('array')
expect(product.tag).to.eql(null)
})
})

0 comments on commit 605ba54

Please sign in to comment.