Code Monkey home page Code Monkey logo

json-api-serializer's People

Contributors

alechirsch avatar alexzherdev avatar alonewarrior avatar chamini2 avatar ckeboss avatar danivek avatar dependabot[bot] avatar derekrliang avatar dynamiccast avatar igneel64 avatar istanful avatar itsfadnis avatar javiertury avatar john-goldsmith avatar mattiloh avatar max-konin avatar medfreeman avatar pzuraq avatar stefanvanherwijnen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

json-api-serializer's Issues

Should be able to return "Resource Identifier Objects"

I try to return a resource identifier object of an entity and to do so I tried to whitelist the 'id' only or to serialize data where data = { id }.

I always end up with the attributes object being empty attributes: {}

Shouldn't there be an option to deactivate attributes or any way to represent the resource identifier only?

Duplicate type + id in included, but different data.

I am using this lib to serialize complex objects that might be referencing the same type, but that referenced object might not necessarily have the same attributes each time it's referenced.

Example:

const obj = {
  tenant: {
    id: '2',
    property: {
      id: '1',
      street: 'whjatever a', 
      place: 'exaplmecity',
    },
  },
  landlord: {
    id: '3',
    property: {
      id: '1',
      street: 'whjatever a', 
      place: 'exaplmecity', 
      lease: 'test',
    },
  },
};

In the above the property is referenced multiple times, but because each time it's referenced, the data usage is different, so not all attributes are required. When the above is serialized it'll include the property twice in included because it's different. I know how to fix it afterwards, but I would love to just be able to flick a switch on json-api-serializer to indicate that I would like it to pro-actively merge the attributes of objects that are of the same type & have the same id.

I do realize that the links might be different due to the relations being different.

Allow relationships to have an alternative key if relationship key not exist

Some ORM (like js-data) have two keys in object for defining a relation :

  • a key with id or ids (unpopulated relation)
  • a key with a populated relation

example for an article with a relation with a user :

{
  "id": "1",
  "title": "Nice article",
  "user_id": "2", // unpopulated user
  "user": { // populated user
    "id": "2",
    "name": "John Doe"
  }
}

If we not explicitly populate relation in the ORM, we only have the user_id key in object.

So, relationships configuration could have an alternative key to watch for unpopulated relationships if the populate relationship key does not exist.

Suggestion: Allow alternativeKey to be a path

In the code here:

data: this.serializeRelationship(rOptions.type, data[relationshipKey], this.schemas[rOptions.type][schema], included, extraData),

Could this change from:

data: this.serializeRelationship(rOptions.type, data[relationshipKey], this.schemas[rOptions.type][schema], included, extraData),

to:

data: this.serializeRelationship(rOptions.type, _.get(data, relationshipKey), this.schemas[rOptions.type][schema], included, extraData),

We have a rather obscure data model where there is a relationship effectively contained under tags.users but I cannot currently specify this as an alternativeKey as a path is not allowed.

Deserializing relationships to an object

The default behaviour of deserialize() seems to be to return an array of relationships keys. If the top-level key "included" is set, it returns the relationships as an object with an 'id' key however.

For example:

{
	"data": {
		"id": 1,
		"attributes": {
			"name": "randomname"
		},
		"relationships": {
			"roles": {
				"data": {
					"type": "role",
					"id": 1
				}
			}
		}
	}
}

deserializes to { id: 1, name: 'randomname', roles: 1 }.

{
	"data": {
		"id": 1,
		"attributes": {
			"name": "randomname"
		},
		"relationships": {
			"roles": {
				"data": {
					"type": "role",
					"id": 1
				}
			}
		}
	},
	"included": [{
		"type": "role",
		"id": 1
	}]
}

deserializes to: { id: 1, name: 'randomname', roles: { id: 1 } }

Now, I would like to get the second result, but the JSON API spec doesn't seem to require the "included" key on updates: https://jsonapi.org/format/#crud-updating-resource-relationships

So I am wondering, is there a specific reason why the result of deserialization differs when the "included" key exists in the request?

deserializeResource fails when blacklistOnDeserialize is set but no attributes are present

When deserializing a patch request for relationships you may encounter a payload that does not include any attributes, see https://jsonapi.org/format/#crud-updating-resource-relationships

This means that this code will fail:

// Remove unwanted keys (blacklistOnDeserialize option)
if (resourceOpts.blacklistOnDeserialize.length > 0) {
data.attributes = _pick(data.attributes, _difference(Object.keys(data.attributes), resourceOpts.blacklistOnDeserialize));
}

Library throws an error on a sample and the `links` field is not included

Hi. Thanks for making a beautiful library. I am trying out to deserialize this JSON Object.(Taken from the official docs of JSON API Spec).

Here is the code:

var JSONAPISerializer = require('json-api-serializer');
var Serializer = new JSONAPISerializer();

Serializer.register('articles', {
  relationships: {
    author: {
      type: 'people',
    },
    comments: {
      type: 'comments'
    }
  }
});

Serializer.register('people', {});
Serializer.register('comments', {
  relationships: {
    author: {
      type: 'people'
    }
  }
});

var json1 = {
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON API paints my bikeshed!"
    },
    "links": {
      "self": "http://example.com/articles/1"
    },
    "relationships": {
      "author": {
        "links": {
          "self": "http://example.com/articles/1/relationships/author",
          "related": "http://example.com/articles/1/author"
        },
        "data": { "type": "people", "id": "9" }
      },
      "comments": {
        "links": {
          "self": "http://example.com/articles/1/relationships/comments",
          "related": "http://example.com/articles/1/comments"
        },
        "data": [
          { "type": "comments", "id": "5" },
          { "type": "comments", "id": "12" }
        ]
      }
    }
  },
  "included": [{
    "type": "people",
    "id": "9",
    "attributes": {
      "first-name": "Dan",
      "last-name": "Gebhardt",
      "twitter": "dgeb"
    },
    "links": {
      "self": "http://example.com/people/9"
    }
  }, {
    "type": "comments",
    "id": "5",
    "attributes": {
      "body": "First!"
    },
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "9" }
      }
    },
    "links": {
      "self": "http://example.com/comments/5"
    }
  }, {
    "type": "comments",
    "id": "12",
    "attributes": {
      "body": "I like XML better"
    },
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "2" }
      }
    },
    "links": {
      "self": "http://example.com/comments/12"
    }
  }]
};

const data = Serializer.deserialize('articles', json1);
console.log(data);

It is throwing the error:

deserializedData[resourceOpts.id] = data.id || undefined;
                                            ^
TypeError: Cannot read property 'id' of undefined

The reason it might be happening is that one of the included resource object of type comments has a relationship with the author having id 2 which is not defined in the compound document. Please clarify on this and explain how to make it work. Also, why aren't the links field deserialized into the resulting object. Please help. Thanks!!

Acceptance of malformed relationships

I noticed that in 62b7386 you are handling malformed relationships by ignoring them. This seems to me a debatable thing to do, since maybe we should be warning the user of the malformed data, rather than ignoring it.

I don't ask for us to check if it's malformed and throw on it, what I would suggest is not check for this at all. JSON API specifies a very clear payload format, so if it is not followed, it's understandable that this package would not work correctly.

What I am trying to say is, why not make the code easier to maintain by accounting for less cases? Maybe I can remove this specific check in #48.

Empty relationships returned as data: null.

The 'solution' for issue #38 seems to have introduced a breaking change in json-api-serializer, and in my opinion is making sure that json-api-serializer does not follow the json:api spec. It also makes sure that the problem faced in #25 is now caused by json-api-serializer, and no longer by improper serialisation to JSON.

The issue:

const JSONAPISerializer = require('json-api-serializer');
const Serializer = new JSONAPISerializer();

// Schools type
Serializer.register('schools', {
  relationships: {
    students: {
      type: 'students',
      links: {
        self: '/students'
      }
    }
  }
});

// Students type
Serializer.register('students', {
  relationships: {
    grades: {
      type: 'grades',
      links: {
        self: '/grades'
      }
    }
  }
});

Serializer.register('grades');

// Input data for schools
const input = {
  "id": "1",
  "name": "School Name",
  "students": {
    id: 1,
  },
};

const output = Serializer.serialize('schools', input);
console.log(JSON.stringify(output));

output:

{
  "jsonapi": {
    "version": "1.0"
  },
  "data": {
    "type": "schools",
    "id": "1",
    "attributes": {
      "name": "School Name"
    },
    "relationships": {
      "students": {
        "links": {
          "self": "/students"
        },
        "data": {
          "type": "students",
          "id": "1"
        }
      }
    }
  },
  "included": [
    {
      "type": "students",
      "id": "1",
      "attributes": {},
      "relationships": {
        "grades": {
          "links": {
            "self": "/grades"
          },
          "data": null
        }
      }
    }
  ]
}

Explanation:
I know you think you're following the spec, but look at what it says:
screen shot 2018-01-11 at 15 08 40

It clearly states that ONE of those three has to be present. Not ALL three with a value of null. This literally broke my API.

My suggestion is to following the common convention regarding missing relationships. Keep data on undefined, so it'll be filtered out on stringify. Make sure that links are included for lazy loading, and if there's metadata present output that as well. If the relationship IS present, but has a value of null then it should be included with data is null.

I am downgrading to v1.9.1 where this change hasn't been included.

Nested Schema

Good day,

If I have the following schema:

"data": [
        {
            "type": "users",
            "id": "1",
            "attributes": {
                "email": "[email protected]",
                "organisations": [
                    {
                        "id": 1,
                        "name": "reggae-org",
                        "roles": [
                            {
                                "id": 2,
                                "name": "self-verify",
                            },
                            {
                                "id": 3,
                                "name": "organisation-sales",
                            },
                            {
                                "id": 4,
                                "name": "organisation-admin",
                            },
                            {
                                "id": 5,
                                "name": "super",
                            }
                        ]
                    }
                ]
            },

How would I specify a schema to include not only the organisations but also the roles?

Thank you,
Regards,
Emir

Adding async serialization to avoid blocking

Hi @danivek!

I really like the flexibility of json-api-serializer and it helped us a lot to add json-api capabilities to our rest-api. But we experienced some serious performance issues on large response-payloads, as the serialization is synchronous and thus blocking the loop for several seconds (depending on the payload-size). For small payloads this is not a real issue, and of course, we could optimize on our side by paginating large requests and thus dividing the long blocking process in several smaller blocking processes. But sometimes it can be very handy to have everything in one request…

What do you think about adding an async interface by returning a promise? To avoid adding breaking changes, we could add another method like Serializer.serializeAsync().

To convert it to a non-blocking operation we could serialize every item of a data-array with a nextTick? Or convert the array to a stream and process this stream until returning the processed payload as promise?

I would like to add this functionality and add a PR, but let's discuss how the API should look like before.

id not defined by a single column

I have resources which have id defined by two different columns (composite keys in DB layer). I was wondering if this project would be interested in a PR to make id on register to be either a column or a function that returns the id.

I mean that it could be:

Serializer.register('article', {
  id: 'id', // backwards compatible way of doing it
  relationships: {
    comments: { type: 'comment' }
  }
});

Serializer.comment('comment', {
  id: function(attributes) {
    return `${attributes.user_id},${attributes.article_id}`
  }
});

That way it would get data like

Serializer.serialize('article', {
  id: 1,
  title: 'This is json-api-serializer',
  comments: [{
    user_id: 4,
    article_id: 1,
    body: 'OMG, cool project!'
  }, {
    user_id: 6,
    article_id: 1,
    body: 'Yeah, cool project!'
  }]
});

Resulting in

{
  "jsonapi": {
    "version": "1.0"
  },
  "data": [{
    "type": "article",
    "id": "1",
    "attributes": {
      "title": "This is json-api-serializer"
    },
    "relationships": {
      "comments": {
        "data": [{
          "type": "comment",
          "id": "4,1"
        }, {
          "type": "comment",
          "id": "6,1"
        }]
      }
    }
  }],
  "included": [{
    "type": "comment",
    "id": "4,1",
    "attributes": {
      "body": "OMG, cool project!"
    }
  }, {
    "type": "comment",
    "id": "6,1",
    "attributes": {
      "body": "Yeah, cool project!"
    }
  }]
}

Every resource object must contain an id member of type string

Hi,

JSON API specification requires resource object to contain an id member of type string. http://jsonapi.org/format/#document-resource-objects.

json-api-serializer simply copies provided unique identifier here : https://github.com/danivek/json-api-serializer/blob/master/lib/JSONAPISerializer.js#L96 but do not care about the type.
In my case, I am trying to serialize data coming out of an ORM where SQL tables' primary keys are set to auto increment, resulting in unique identifiers of type number.

Do you think this is the role of json-api-serializer to try to call toString() in case given identifier is not of type string ? As this is required by the spec, I would expect a serializer to do it.

Any thoughts ?

JSON API recommend to use "-" as separator between multiple words

Hi,

While not explicitly required by the spec, JSON API advises that :

Member names SHOULD contain only the characters “a-z” (U+0061 to U+007A), “0-9” (U+0030 to U+0039), and the hyphen minus (U+002D HYPHEN-MINUS, “-“) as separator between multiple words.

Source : http://jsonapi.org/recommendations/#naming

json-api-serializer treats attributes's keys as they are and do not modify them to follow this recommendation.

I work daily with Ember.js which by default is configured to talk with a JSON API interface. This framework expects multiple words attributes to be separated with a "-". Then when it de-serializes, it gives attributes's keys a camelCase form.

Do you think json-api-serializer should follow this recommendation and decamelize attributes's key when serializing ?
Or maybe this is the role of the code using this module to provide objects with keys in the format wanted ? Though it is not very convenient to deal with variables containing a dash in Javascript. (Perhaps this is why Ember chose to de-serialize objects to camelCase keys).
If not flexible enough, this could also be an option to pass to the serializer.

Any thoughts ?

dynamic type

Hi there,

I can see that it's possible to change the type dynamically by passing in a configuration to the serializer itself. Is this possible with relationships?

My use case is that I have a campaign model that has a relationship recipients. These recipients can be of type staff or customer.

Is this possible with the current implementation?

Thanks!

jsonapiObject: false throwing error

Hi, I'm attempting to disable the json api version in the payload, but getting an error when trying to do so.

const JSONAPISerializer = require('json-api-serializer');

const Serializer = new JSONAPISerializer({
    convertCase: 'camelCase'
});

Serializer.register('campaign', {
    jsonapiObject: false
});

Receiving the following error:

Error: ValidationError: "jsonapiObject" is not allowed
    at JSONAPISerializer.validateOptions (/Users/jamesdixon/Projects/scout/platform/api/node_modules/json-api-serializer/lib/JSONAPISerializer.js:61:13)
    at JSONAPISerializer.register (/Users/jamesdixon/Projects/scout/platform/api/node_modules/json-api-serializer/lib/JSONAPISerializer.js:108:56)
    at Object.<anonymous> (/Users/jamesdixon/Projects/scout/platform/api/handlers/campaign.js:10:12)

Am I missing something?

Thanks for the great library!

Dinamically avoid certain fields in certain JSON-API response

When I return a response that contains no attributes, but only the id values of the data,the attributes field still appears even if it is blank.

Basically the same thing applies to relationships. If I have defined relationship in the registered model it seems there is no way for me to send a response without the data. The only thing I can do is setting that link to null by responding null in the functions responsible to handle links.

GET example.com/v1/bands/1/relationships/musicians

{
    "jsonapi": {
        "version": "1.0"
    },
    "links": {
        "self": "http://localhost:12345/v1/bands/1/relationships/musicians"
        "related": "http://localhost:12345/v1/bands/1/musicians"
    },
    "data": [
        {
            "type": "musician",
            "id": "1",
            "attributes": {} <-- I have selected only the id in the query to the db, but still get this
           "relationships": {
                "bands": null <-- would like to avoid the field relationship at all in this case
            },
        }
    ]
}

Is there a way for me to do this?

Cheers

Ignore if missing

I was wondering if you'd be interested in adding an option to skip that data attribute in relationships if it is missing.

If a school has many students. When I return the school, I want the links to get the students to be included but not the actual data.

// school
{
  id: 1,
  name: 'bla'
  // no students here
}
{
  data: {
    attributes: [],
    id: 1,
    type: 'schools',
    relationships: {
      students: {
        data: null, // I don't want that
        links: {}
      }
    }
  }
}

Something like:

Serializer.register('school', {
  id: 'id',
  relationships: {
    students: {
      type: 'student',
      skipDataIfMissing: true,
      links: {
        related: (school) => `/schools/${school.id}/students`
      }
    }
  }
});

Thanks

Error deserializing null relationships

From http://jsonapi.org/format/#crud-updating-to-one-relationships, I understand that a relationship can have a null value:

const JSONAPISerializer = require('json-api-serializer');
const Serializer = new JSONAPISerializer({
    convertCase: 'kebab-case',
    unconvertCase: 'snake_case'
});

Serializer.register('requests', {
    id: 'reference_code',
    relationships: {
        coupon: {
            type: 'coupons'
        }
    }
});

Serializer.register('coupons', {
    id: 'code',
    relationships: {
        requests: {
            type: 'requests'
        }
    }
});

const payload = Serializer.deserialize('requests', {
    "data": {
        "id":"50696f63-3f61-41ea-aee2-8512295675c7",
        "type": "activity-requests",
        "relationships": {
            "coupon": { "data": null }
        }
    }
});

But this throws:

TypeError: Cannot read property 'id' of null
    at Object.keys.forEach
    at Array.forEach (<anonymous>)
    at JSONAPISerializer.deserializeResource
    at JSONAPISerializer.deserialize

Missing dependency

I'm wanting to use this in a Vue.js app (using webpack) and whenever I import it:

import JSONAPISerializer from 'json-api-serializer'

I get the following error:

This dependency was not found:

* dns in ./node_modules/isemail/lib/index.js

To install it, you can run: npm install --save dns

I tried doing what it asks, but got:

error [email protected]: The engine "node" is incompatible with this module. Expected version "0.8.x".

So I added the --ignore-engines flag, which installed it, but now I get:

 warning  in ./node_modules/defaultable/defaultable.js

49:13-31 Critical dependency: the request of a dependency is an expression

So, is there anything I can do to get this working?

Deserialize async?

I see there is serializeAsync but I don't see deserializeAsync.. Is this wanted? Am I missing something?

Loop associations produce invalid included relationships

Hi,

Once again, thanks for this great module !
Today, I encountered a tricky use case.
I have the following many to many relationship:

Pets have many homes (of type Houses)
Houses have many pets (of type Pets)

When I try to serialize the following :

Serializer.serialize("pets", {
    "homes": [{
        "city": "Paris",
        "id": 2
    }],
    "name": "Dushi",
    "color": "white",
    "id": 2
});

I have this result:

{
    "data": {
        "type": "pets",
        "id": "2",
        "attributes": {
            "name": "Dushi",
            "color": "white"
        },
        "relationships": {
            "homes": {
                "data": [{
                    "type": "houses",
                    "id": "2"
                }]
            }
        }
    },
    "included": [{
        "type": "houses",
        "id": "2",
        "attributes": {
            "city": "Paris"
        },
        "relationships": {
            "pets": {
                "data": []
            }
        }
    }]
}

The problem is the data record defines a relationship with Houses (via homes), but the included Houses defines no relationships with Pets.

This means depending on where the piece of code receiving the serialized json is looking for a relationship, there is a chance it misses the association between Pets with id 2 and Houses with id 2.
By the way, this is the case with Ember.js which is a frontend framework expecting to work with a JSON API compliant backend by default.

The correct output JSON would be:

{
    "data": {
        "type": "pets",
        "id": "2",
        "attributes": {
            "name": "Dushi",
            "color": "white"
        },
        "relationships": {
            "homes": {
                "data": [{
                    "type": "houses",
                    "id": "2"
                }]
            }
        }
    },
    "included": [{
        "type": "houses",
        "id": "2",
        "attributes": {
            "city": "Paris"
        },
        "relationships": {
            "pets": {
                "data": [{
                    "type": "pets",
                    "id": "2"
                }]
            }
        }
    }]
}

What do you think ?

Feedback

Hi,

After getting tremendously frustrated at jsonapi-serializer I decided to try your library and so far so good. A real joy to use, very simple and yet it does what you expect it to. Anyway I wanted to make couple suggestions and see if there is interest:

  • This line would benefit from this checking. It would prevent this kind of crash:
Debug: internal, implementation, error 
    TypeError: Uncaught error: Cannot read property 'limited' of undefined
    at Object.keys.forEach (/project/node_modules/json-api-serializer/lib/JSONAPISerializer.js:433:134)
  • Casing usually is consistent throughout the project. What do you think of making convertCase and option of the JSONAPISerializer instance? That way no need to repeat myselft.
const Serializer = new JSONAPISerializer({
  convertCase: 'kebab-case',
  unconvertCase: 'caseCase'
});

I might have more things as I barely got started. I can make a PR if this is sounds like something you'd want.

TypeScript Definitions

Hey there,
i am currently evaluating this package to be used in a TypeScript REST API. So i was wondering, if there are some TypeScript Definitions available?!

All the best

Empty relationships should have data key with value null

Per spec: http://jsonapi.org/format/#document-resource-object-relationships A “relationship object” MUST contain at least one of the following: links, data, meta. Implementations I've seen in the past will have "posts": { "data": null } } within the relationships object if the relation doesn't exist/isn't provided.

However with schema like

module.exports = {
  whitelist:     ['name'],
  relationships: {
    players: { type: 'players' },
    turns:   { type: 'turns' },
    map:     { type: 'maps' },
  },
};

my json comes out like

{
    "jsonapi": {
        "version": "1.0"
    },
    "data": {
        "type": "campaigns",
        "id": "10",
        "attributes": {
            "name": "My New Campaign"
        },
        "relationships": {
            "players": {},
            "turns": {},
            "map": {}
        }
    }
}

I'm saying it should be like

"relationships": {
    "players": { "data": null },
    "turns": { "data": null },
    "map": { "data": null }
}

I looked through the source to see if I could make a PR but I couldn't find where this is happening... It seems like at the very least from https://github.com/danivek/json-api-serializer/blob/master/lib/JSONAPISerializer.js#L582 it should have data: undefined

Attributes becomes an object to id when related

Thanks for this great serializer! Works great for my needs except from this one big thing:

When I have data like this:

{
    "id": 246,
    "parent": null,
    "document": 1,
    "product": null,
    "name": "Engelska",
    "type": "products",
    "template": null,
    "metadata": null,
    "sort": null,
    "status": null,
    "created": "2016-07-07T11:52:16.237Z",
    "updated": null,
    "tags": [
        {
            "id": 6,
            "parent": null,
            "name": "Gymnasiet",
            "slug": "gymnasiet",
            "displayname": "Gymnasiet",
            "image": null,
            "metadata": null,
            "type": "age_groups",
            "created": "2016-07-07T11:27:35.386Z",
            "updated": null
        },
        {
            "id": 18,
            "parent": null,
            "name": "Testkategori",
            "slug": null,
            "displayname": null,
            "image": null,
            "metadata": null,
            "type": null,
            "created": "2016-07-08T11:32:05.471Z",
            "updated": null
        }
    ]
}

and my serializer looks lite this:

Serializer.register('node', {

  id: 'id',
  topLevelLinks: { 
    self: 'http://localhost:3000/api/v1/nodes' 
  },
  links: { 
    self: function(data) {
      return 'http://localhost:3000/api/v1/nodes/' + data.id;
    }
  },
  relationships: {
    tags: {
      type: 'tag', 
    }
  },
  convertCase: "kebab-case"        
});

Serializer.register('tag', { 
  id: 'id',
  convertCase: "kebab-case",
});

The results becomes quite awkward:

{
    "jsonapi": {
        "version": "1.0"
    },
    "links": {
        "self": "http://localhost:3000/api/v1/nodes"
    },
    "data": {
        "type": "nodes",
        "id": 246,
        "attributes": {
            "parent": null,
            "document": 1,
            "product": null,
            "name": "Engelska",
            "type": "products",
            "template": null,
            "metadata": null,
            "sort": null,
            "status": null,
            "created": "2016-07-07T11:52:16.237Z",
            "updated": null
        },
        "relationships": {
            "tags": {
                "data": [
                    {
                        "type": "tag",
                        "id": {
                            "id": 6,
                            "parent": null,
                            "name": "Gymnasiet",
                            "slug": "gymnasiet",
                            "displayname": "Gymnasiet",
                            "image": null,
                            "metadata": null,
                            "type": "age_groups",
                            "created": "2016-07-07T11:27:35.386Z",
                            "updated": null
                        }
                    },
                    {
                        "type": "tag",
                        "id": {
                            "id": 18,
                            "parent": null,
                            "name": "Testkategori",
                            "slug": null,
                            "displayname": null,
                            "image": null,
                            "metadata": null,
                            "type": null,
                            "created": "2016-07-08T11:32:05.471Z",
                            "updated": null
                        }
                    }
                ]
            }
        },
        "links": {
            "self": "http://localhost:3000/api/v1/nodes/246"
        }
    }
}

As you can see, the tag object becomes appended to the ID, and the tags doesnt get in the included key.

Any idea of what can cause this?

Client side deserialization

Hello and thanks for your package
I have two question:

  1. Can this package be used as client side serializer/deserialzer?
  2. If yes does it handle included part?
    Your help would be appreciated

behavior when data is null or empty

Hi,

While upgrading my project with json-api-serializer, I noticed a few tests failing when testing that an endpoint returns no data. For example, if someone requests a list of campaigns and there is no data, I'm seeing the following response:

{ 
 jsonapi: undefined,
  meta: undefined,
  links: undefined,
  data: [],
  included: undefined 
}

The data portion is JSONAPI-compliant, but not sure about the rest. I actually have jsonapiObject set to false and I have no meta, links or included. Here's my registration:

Serializer.register('campaign', {
    jsonapiObject: false,
    blacklist: ['batchId'],
    relationships: {
        business: { type: 'business', alternativeKey: 'businessId' }
    }
});

I'm not seeing anything in the spec that points to these attributes being undefined if they don't exist. I think the only place that may make sense is, for example, if you have a relationship that's empty, you might have data: null. Otherwise, it seems extraneous and adds up to unneeded bytes being sent across the network.

Thoughts?

Btw, I'm running 1.12.0.

whitelist and blacklist rules on deserialize

Wondering if there are plans (or it is already implemented but im doing it wrong) for blacklist and whitelist rules to apply to deserialize. Currently it seems to be outputting a deserialized version of the data regardless of these rules. I am having to deserialize, serialize and then deserialize to get the clean data.

deserialize Included block

Hi,

So far this library has been fantastically useful. However...

Unless I have misread something, I don't believe JSONAPISerializer.deserialize(type, data) will do anything with the included resources.

I think it should be possible to deserialize the included resources first and then pass those in to deserializeRelationships and set that on the deserializedData[relationshipKey].

If this is something that sounds sane I will try and put together a PR with the above change.

Thanks.

Example of a custom schema?

Is there any way an example of a custom schema could be added to the docs? We were hoping to slightly modify the relationships key to always return an array of items instead of the current format:

{
	"id": "c82452b7-c3c3-5551-8bef-22a73f9793bb",
	"type": "alerts",
	"attributes": {
		...
	},
	"relationships": {
		"article": {
			"data": {
				"id": "cc19857c-01eb-5c57-b730-be1a05ec54e9",
				"type": "articles"
			}
		}
	}
}

to

{
	"id": "c82452b7-c3c3-5551-8bef-22a73f9793bb",
	"type": "alerts",
	"attributes": {
		...
	},
	"relationships": {
		"items": {
			"data": [
                            {
				"id": "cc19857c-01eb-5c57-b730-be1a05ec54e9",
				"type": "articles"
			    }
                       ]
		}
	}
}

I know this doesn't match the JSON API schema spec, but it is a simpler format for our client apps to consume.

Pass data and extra options to all functions in a schema

I want to build links for a resource using the request object from express, but the links option in schemas does not get passed options like topLevelLinks does.

Seems like any function in a schema should get passed both data and options, like this:

const Serializer = new JSONAPISerializer();

Serializer.register('message', {
  whitelist: ['body','created_at'],

  // currently only accepts an options argument :(
  topLevelLinks: function(data, options) {
    let lastRecordId = data[data.length-1].id;
    return {
      next: `${options.req.get('host')}${options.req.baseUrl}/messages?older_than=${lastRecordId}`
    }
  },

  // currently only accepts a data argument :(
  links: function(data, options){
    return {
      self: `${options.req.get('host')}${options.req.baseUrl}/messages`
    }
  }
});

let messages = serializer.serialize('message', results, {req});

Perhaps even the entire schema could be a function

Serializer.register('message', function(data, options) {
  return {
    ...
  }
});

Best approach to serialize an array containing different types?

I'm creating a search API service for a system that has various types of documents in it returned in response to a query sorted by relevency, so the "data" element of the top level JSON:API response will contain multiple object of varying types (books, articles, whitepapers, etc).

Serializers seem to only support serialization of one type at a time and appear to ignore the "type" field specified by an object in an array. For example a query might return objects in the following order [Book, Article, Book, Book, Whitepaper]. Using the json-api-serializer, which approach is best for making sure each of those returned types is serialized properly as objects returned in "data"?

Thank you for your time!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.