Code Monkey home page Code Monkey logo

devour-client's People

Contributors

arnezsng avatar auspicus avatar auvipy avatar billxinli avatar danwarner avatar davidpellerin avatar dependabot[bot] avatar emerson avatar ftaiolivista avatar glsignal avatar graemetait avatar gregpeden avatar ibustosatlegalzoom avatar idragonfire avatar jrombi avatar k8n avatar kud avatar masimons avatar randym avatar samtgarson avatar solidgoldpig avatar sonnn avatar spiderbites avatar stephenkubovic avatar themarkappleby avatar tijn avatar tomers avatar wolfgang42 avatar zchrykng avatar zenchild 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

devour-client's Issues

Request with POST or PATCH doesn't work

Hi.

When you try to perform an arbitrary request with methods PATCH or POST, you end up getting an error: TypeError: Cannot read property 'options' of undefined.
I've tracked this down to the _serialize.js file, method resource. The problem is that in line 11 let model = this.modelFor(modelName) since we are not providing a model, the model variable is undefined and when we call model.options latter, the error is triggered.

Ex of calling code: jsonApi.request('https://example.com', 'POST', { a_query_param: 3 }, { some_payload_item: 'blah' })

Thanks

[Question] Trailing slashes support?

I was going to create a PR to add a constructor option for building URLs with trailing slashes, but I wanted to check first if there was another solution I was missing.

Ignore null parameters

It would be nice to be able to set null for the value of include for example, and have the resulting request just not include that param. That way it would be possible to concisely decide to specify an include or not.

Create action with relationship

Hey,

I am trying to send a create action with a relationship but the relationship does not include the data under it. This is what I did:

jsonApi.create('user/properties', {
    address: {
      street_number: '1',
      street_name: 'name',
    },
    headline: 'something'),
    description: 'description'),
    photos: [],
    floorplans: [],
  })

What I get on the server side is this:

'data': {
   'type': "user/properties"
   'attributes': "the attributes - everything is fine here"
   'relationships': {
       'address': {
          'data': {
            'type': 'addresses'
         }
      }
   }
}

As you can see the data is missing under the address. Am I doing something wrong?

Thanks!

Receiving: undefined is not an object (evaluating 'source.pointer')

I'm trying to have devour (v2.0.7) receive following response in an RN app:

{
  "errors":[
    {
      "title":"Authentication failed",
      "detail":"Invalid username and/or password",
      "code":"101",
      "status":"400"
    }
  ]
}

but, I'm seeing the following error:

undefined is not an object (evaluating 'source.pointer')
- node_modules/devour-client/lib/middleware/json-api/res-errors.js:46:13 in errorKey
- node_modules/devour-client/lib/middleware/json-api/res-errors.js:24:24 in buildErrors
- ... 10 more stack frames from framework internals

I'm new to JSON API, so looking at the docs (http://jsonapi.org/format/#error-objects) I noticed it said an error object MAY have one or more attributes, instead of MUST as used elsewhere. So just wondering if this is still correct?

Otherwise, looking at that code, maybe it's worth checking if source is present as well?

function errorKey(index, source) {
  if (!source || source.pointer == null) {
    return index;
  }
  return source.pointer.split('/').pop();
}

Env

Devour 2.0.7
RN 0.50.3

Nested resource URLs

@themarkappleby pointed out an issue that we need to figure out – especially since it's a valid JSON-API convention.

When fetching a resource, it's perfectly valid to do so through a nested URL, you can see a clear example of this articulated in the specification here.

And the following request fetches an article’s author:
GET /articles/1/author HTTP/1.1

Right now, our find calls just accept the name of the model jsonApi.find('author', 1)... so what's the best way to support this feature?

@themarkappleby was thinking we could parse a raw string jsonApi.find('articles/1/author'), but I'd be a little worried about model names vs urls and figuring out how to map all that back.

I was thinking we could maybe pass an object in some instances:

jsonApi.find({model: 'author', url: 'articles/1/author'}, 1)

Or maybe an options object?

jsonApi.find('author', 1, {nested: 'articles/1'})

Happy to hear any thoughts about this – @derek-watson I know you are questioning the requirements of having defined models all together (I still need to respond to that)

Hot Logo

We need a logo. Thinking we can just buy one off vector stock or something... Drop your suggestions in here.

Singleton pattern

I'm not sure I understand the way the singleton pattern is used here. In the readme I'm encouraged to

let jsonApi = JsonApi.getInstance()
jsonApi.setup('http://your-api-here.com')

which made me think I'm getting a new instance of JsonApi and configuring it with an endpoint URL (I realized later that's not the case). If we're getting and configuring instances, I think it would be most appropriate to use the new keyword and pass options to the constructor:

const jsonApi = new JsonApi({baseUrl: 'http://your-api-here.com'})

I looked at the code to double-check and saw this, which confirmed my suspicions:

class JsonApi {
  ...

but when I looked into the code for the getInstance() method, I realized we're forcing a singleton pattern.

  1. If using a singleton pattern, I suggest using an object literal instead of getting fancy with making a class and forcing users to use a misleading getInstance() method
  2. I'm not sure a singleton is appropriate - wouldn't you want to ever have two objects concurrently, configured against different endpoints?

Unescaped characters error when parameter values have spaces in

Demo: https://runkit.com/jon-hall/59b966684249c500125ad282 (see the terminal output for the actual error)

When making a findAll request that has filters, and any of the filter values has a space in, the following error is being thrown:

devour error TypeError: Request path contains unescaped characters
    at new ClientRequest (_http_client.js:52:11)
    at Object.exports.request (http.js:31:10)
    at Writable.RedirectableRequest._performRequest (/app/available_modules/1505322364000/devour-client/node_modules/axios/node_modules/follow-redirects/index.js:73:20)
    at Writable.RedirectableRequest (/app/available_modules/1505322364000/devour-client/node_modules/axios/node_modules/follow-redirects/index.js:57:7)
    at Object.wrappedProtocol.request (/app/available_modules/1505322364000/devour-client/node_modules/axios/node_modules/follow-redirects/index.js:229:10)
    at dispatchHttpRequest (/app/available_modules/1505322364000/devour-client/node_modules/axios/lib/adapters/http.js:131:25)
    at httpAdapter (/app/available_modules/1505322364000/devour-client/node_modules/axios/lib/adapters/http.js:18:10)
    at dispatchRequest (/app/available_modules/1505322364000/devour-client/node_modules/axios/lib/core/dispatchRequest.js:52:10)
    at process._tickCallback (internal/process/next_tick.js:109:7)
    at Module.runMain (module.js:606:11)
    at run (bootstrap_node.js:389:7)
    at startup (bootstrap_node.js:149:9)
    at bootstrap_node.js:504:3

How to handle api errors

I'm trying to use your client, I'm using promises but have no idea how to handle errors back from the API, your documentation isn;t very clear, could someone point me in the right direction?

I'm currently implementing like this:

jsonApi.create('genre', genre).then((response) => {
 console.log(response)
})

If there is an error returned from the API then no response is consoled. I tried using catch but that doesn't return the response from the serve.

Any help would be greatly appreciated!

Not handling valid JSON API response properly

According to the JSON API spec here a valid response to an PATCH request is status 204 and an empty body. This is how the fortune-json-api library handles these requests.

I will be looking into how to patch this, but would appreciate help/advice.

Defining models and attributes

// Define Model
jsonApi.define('post', {
  title: '',
  content: '',
  tags: []
})

@Emerson why is this step necessary? I'm unable to find any reference to the models and attributes being used in the codebase. Are there roadmap features that will make use of this? Is it useful on the client?

JSPM only works with import 'devour-client/lib'

I just started a JSPM angular 2 project (according to this project).

Installing devour client: jspm install npm:devour-client works. When I need it in a component it only works when I use import JsonApi from 'devour-client/lib';

Am I missing something or is there something wrong regarding the packaging of this module?

Caching side effects

The caching from @nicooga 44701c4 has some unexpected side effects ...

Example

You first request is Entity A
Your second request is Entity A again with some included relationships, e.g. SubEntityA
The cache is used for Entity A and SubEntityA is null, but it was send to the Client ...

npm installation guide should use the new package name

The npm installation guide refers to "devour-api-client", but I believe the new name is "devour-client".. There are two areas of the Quick Start guide that should be updated:

npm install devour-api-client --save 

import JsonApi from 'devour-api-client'

Support fetch

Would it be a good idea to use fetch under the hood instead of axios?

fetch is a better networking API being worked on by the standards committee and is already available in Chrome. It is available in React Native by default.

https://fetch.spec.whatwg.org/
https://facebook.github.io/react-native/docs/network.html

Here's a polyfill that can be used until native runtime support for fetch is widespread, which comes in at 11kb of unminified code instead of 32kb for axios, with the upside that the dependency disappears completely at some point in the future:

https://github.com/github/fetch

model reuse

Hi,
Do you have any example of multiple model definition of model reuse? How and where to move models definition out of the main logic to use them multiple times in different files?

Thanks

Pull request template

I'd like to consider removing the pull request template from this project. I find clear and concise english to be a much more expressive way to describe the intention of your PR, and in many cases the template is getting in the way of clarity.

Here is a full-screen desktop screenshot of a recent pull request. In my mind that amount of screen real estate should contain a lot more information.

screen shot 2016-05-07 at 1 11 21 pm

Wrong Accept Header

Your API have a wrong Accept Header

 payload.req.headers = {
	        'Content-Type': 'application/vnd.api+json',
	        'Accept': 'application/vnd.api+json'
	      }

Accept should be e.g. application/json otherwise it returns a 406 Not Acceptable
see Specification: http://jsonapi.org/format/#content-negotiation-servers

image

Hotfix

jsonApi.headers['Accept'] = 'application/json';

Add a relationships() method to url builder

Hi

According to JSON API spec, you can update a relationship by using the "relationships" link ex post/1/relationships/comments.
Currently Devour only allows this through the resource link post/1 by adding the respective relationship object in the data sent to the server.
If we add a method similar in behavior to all and one to the url builder we could allow relationships links to work.
Ex

relationships () {
    this.builderStack.push({path: 'relationships'})
    return this
}

After this we could do something like jsonApi.one('post', 1).relationships().all('comments').post([{id: comment1Id}, {id: comment2Id}])

The "relationships" url could be configurable to allow more flexibility.
What do you think?

Error importing JsonApi in React Native running in Expo

Not sure if this is the right place to report this - I'm trying to use this library in a react native app started with create-react-native-app (to host in Expo), and the very first statement:

import JsonApi from 'devour-client';

is erroring when trying to open the app in a device with:

console.error: "There was a problem sending log messages to your development environment",
 {
  "line":53577,
  "column":38,
  "sourceURL":"http://192.168.8.100:19003/node_modules/react-native-scripts/build/bin/crna-entry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/erik/Coding/rn-devour-app/node_modules/expo/tools/hashAssetFiles"}

<unknown>
    RemoteConsole.js:121:6
tryCatch
    es6-promise.js:410:20
invokeCallback
    es6-promise.js:425:21
publish
    es6-promise.js:393:21
publishRejection
    es6-promise.js:335:10
flush
    es6-promise.js:121:13
_callTimer
    JSTimers.js:154:6
callTimers
    JSTimers.js:411:17
__callFunction
    MessageQueue.js:302:47
<unknown>
    MessageQueue.js:116:26
__guard
    MessageQueue.js:265:6
callFunctionReturnFlushedQueue
    MessageQueue.js:115:17

I noticed in the docs I can pass logger: true|false to new JsonApi(), but are there calls to log already during the import itself?

Conf

Devour: 2.0.7
Sample app: https://github.com/erikse/rn-devour-app

How to use URLBuilder with Sparse Fields

In Devour documentation I can't find way to add Sparse Fields to my request. I tried something like this:
jsonApi.all(teams).get({fields: '[team]=name'})
but this generate http address:
http://apiurl/teams/?fields=[team]=name instead of http://apiurl/teams/?fields[team]=name
This additional '=' in url (between fields and [team]) isn't according with JsonApi specification. How can I generate proper arguments in url as below:

http://apiurl/teams/?fields[team]=name

Requested entity not inserted in relations

While investigating #82 I found another bug

If you ask for an entity, e.g. clan with `id: 21´,
all releations are inserted correctly, except the entity itself

image

Problem

relatedItemsFor only checks the include part of response, not the cache ...

appending .json to urls

rails controller actions that respond to both html and json require a .json appended to the end of the url to signify that a json response is expected.

addressing this by adding a 'trailingJson' option for the new JsonApi constructor is straightforward and I can add a PR, but is there something wrong w/ this approach?

Initializer should be an option

Initializer should be an option.

Current:
new JsonApi('http://example.com', listOfMiddleware)

The issue with this is that the minute we want to pass in additional option, maybe a header, or enable or disable logging, it becomes a headache to manage, and any other calls of the initializer will need to be changed. Where as with an option, we can easily add a key.

Question: formating dates

Heyhey,
at first: Thank you very much for this great library!

I have the following question and thought that maybe someone has an easy answer because I am actually quite new to this jsonApi thing.

My api formats the dates according to this standard: https://www.w3.org/TR/NOTE-datetime (which i could change if that would help)
I've got a datepicker that needs the date as JavaScript Date Object.
Now I convert the dates, everytime i make a get request and everytime i make an update request.
I also tried using a custom derserializer but than I have to do the whole deserializing process on my own, even though i only need to manipulate one or two attributes.
should i maybe build a middleware for this?

Thank you in advance :)

RangeError: Maximum call stack size exceeded(…) when deserializing relationships that are inter-related

I have the following schema:

  ApiStore.define("user", {
    email: "",
    first_name: "",
    last_name: "",
    external_avatar_url: "",
    phone_numbers: {
      jsonApi: "hasMany",
      type: "phone_number"
    },
    geo_points: {
      jsonApi: "hasMany",
      type: "geo_point"
    }
  });

  ApiStore.define("phone_number", {
    number: "",
    dont_call: "",
    users: {jsonApi: "hasMany", type: "user"}
  });

  ApiStore.define("ttc_interaction", {
    kind: "",
    telemarketer_id: "",
    phone_number_id: "",
    metadata: {},
    date: "",
    telemarketer: {jsonApi: "hasOne", type: "user"},
    customer: {jsonApi: "hasOne", type: "user"},
    phone_number: {jsonApi: "hasOne", type: "phone_number"}
  });

When retrieving ttc_interaction, devour explodes with a RangeError: Maximum call stack size exceeded(…). I assume this is due to a loop caused by the way devour deserializes data, since removing users from phone_numbers "solves" the issue.

Support for hasOne relationship in url builder

Right now I don't see how I can use the url builder to get the url for a resource of hasOne relationship. For instance, if an author has one bio, I would expect the url (for author id 1) to be
authors/1/bio.

I would like to get this url via the url builder methods by doing something like
jsonApi.one('authors', author.id).only('bio').get();.

In the meantime, I can get around this by defining a collectionPath for bio of bio, and doing 'jsonApi.one('authors', author.id).all('bio').get() but that feels like a bit of a hack.

I'd be happy to do the work on this, but wanted to see if you thought it was worthwhile before pursuing it. Also not sure how this might relate to #46.

Serialization of empty/null relationships in post, patch etc.

First up: thanks for the work on this library; it's proving very useful 😄 🎉

I've noticed something that isn't quite to spec when attempting to create/update a resource, specifically how the serializer deals with relationships that either aren't present or are explicitly set to null.

Based on my interpretation of the spec for creating resources and updating relationships, an API expects relationships in a payload, null or otherwise, to contain a data key.

If a relationship is provided in the relationships member of the resource object, its value MUST be a relationship object with a data member

Problem

The current serializer, however, omits the data part, causing the payload to not be valid under version 1 of the spec.

As a quick example, I have two resources (comment, thread) declared as such:

jsonApi.define('thread', {
  thread: {
    jsonApi: 'hasMany',
    type: 'comment'
  }
});

jsonApi.define('comment', {
  body: '',
  thread: {
    jsonApi: 'hasOne',
    type: 'thread'
  }
});

and I want to create a comment that isn't in any thread by doing the following:

jsonApi.all('comment').post({ body: "An orphaned comment", thread: null });

I'd expect the following to be sent to the server

{
  "data": {
    "type": "comments",
    "attributes": { "body": "An orphaned comment" },
    "relationships": {
      "thread": {
        "data": null
      }
    }
  }
}

However what is sent is slightly different (lack of data in the relationship)

{
  "data": {
    "type": "comments",
    "attributes": { "body": "An orphaned comment" },
    "relationships": {
      "thread": null
    }
  }
}

And omitting the relationship entirely:

jsonApi.all('comment').post({ body: "An ambiguous comment" });

Expected:

{
  "data": {
    "type": "comments",
    "attributes": { "body": "An ambiguous comment" }
  }
}

results in the same invalid payload being sent.

Solution

I'm having a think about some ways to change this behaviour in the serializer for the two cases here (deliberately setting it to null, and omitting it entirely). This'll come in a PR at some point in the future, but for now do any thoughts or concerns come to mind if the serializer does get changed to produce the expected behaviour?
This is implemented in PR #30, any feedback or design queries are 👍 👌 😄

Serialization of Document and Resource level meta and link objects

The Challenge

The specification states that both the top level document and any resource may contain meta and links members. However, the deserialization here will nuke any resource specified meta or links members via the top level document's data attribute when deserializing a single resource. (e.g. jsonApi.get('posts', 1))

example 1:

data: {
  attributes:{
    someAttribute: 'a'
  },
  type: 'posts',
  id: '1'
  meta: {
    postMeta: 'some meta data for this individual post'
  }
},
meta: {
  docMeta: 'document meta'
}

Note how both the document and resource have meta members.

As of this PR: #24
resources are deserialized with an understanding of meta and links members. This works fine when handing a collection of resources or resources in included.

However, when defining meta data on a single resource response as shown in example 1 above,
the res-deserialize middleware will replace any resource level meta data with top level meta, or undefined no top level meta data is specified.

https://github.com/twg/devour/blob/master/src/middleware/json-api/res-deserialize.js#L35

The payload from example 1 above deserializes to the following object:

{
  id: '1',
  someAttribute: 'a',
  meta: {
    docMeta: 'document meta'
  }
}

Note how the resource level meta is replaced with the document level meta data.

example 2

data: {
  attributes:{
    someAttribute: 'a'
  },
  type: 'posts',
  id: '1'
  meta: {
    postMeta: 'some meta data for this individual post'
  }
}

The payload for example 2 deserialized to the following object:

{
  id: '1',
  someAttribute: 'a'
  meta: undefined
}

The examples above also apply to resource/document level links members.

Possible Solutions?

Change the deserialized data structure

This is a non-backwards compatible change. While it does provide an arguably more accurate data structure I would be cautious of forcing existing users to rewrite their applications.

{
  resource: {
    attributes: {},
    meta: {},
    links: {}
  },
  meta: {},
  links: {}
}

collections would continue to add meta and links attributes to the array of resources.

Use docMeta and docLinks attributes on the deserialized object

This allows backwards compatibility and help to highlight that there are document level meta and links members.

{
  attributes: {},
  meta: {},
  links: {}
  docMeta: {},
  docLinks: {}
}

collections would add docMeta and docLinks attributes to the array of resources.

Merge the meta/links for single resource documents.

Too risky as there could easily be meta or link members with identical names.

I'm currently working off a fork that utilizes docMeta and docLinks, but before considering a PR I'd like to get some feedback or alternative proposals from the maintainers.

Branding

This library is awesome!

I wonder if it would hit the ear better if it were named simply devour.js. The name as it stands, while descriptive, is a little bit hard to say.

Relationships null

Apologies if I'm doing something wrong here, but I can't figure out what that might be. I have models user and character:

    this.jsonApi.define('user', {
      name: '',
      about: '',
      waifuOrHusbando: '',
      waifu: {
        jsonApi: 'hasOne',
        type: 'characters'
      },
      gender: '',
      location: '',
      birthday: '',
      createdAt: '',
      followersCount: '',
      followingCount: '',
      avatar: { medium: '' }
    })

    this.jsonApi.define('character', {
      name: ''
    })

When I attempt to find the user based on id, the returned user object has null for waifu:

    this.jsonApi.find('user', id, {
      include: 'waifu',
      fields: {...}
    })

Here is what the actual resource looks like:

{
  "data": {
    "id": "78332",
    "type": "users",
    "links": {
      "self": "https://kitsu.io/api/edge/users/78332"
    },
    "attributes": {
      "name": "matthewdias",
      "pastNames": [],
      "about": "People call me an anime normie and a music elitist. I program shit.\n\nI use advanced ratings.",
      "bio": "",
      "aboutFormatted": "I should probably put something here...",
      "location": "Austin, TX",
      "waifuOrHusbando": "Waifu",
      "followersCount": 108,
      "createdAt": "2015-02-03T22:13:20.776Z",
      "facebookId": "1457594844",
      "followingCount": 144,
      "lifeSpentOnAnime": 67445,
      "birthday": "1995-10-25",
      "gender": "male",
      "updatedAt": "2017-05-05T03:57:05.912Z",
      "commentsCount": 460,
      "favoritesCount": 70,
      "likesGivenCount": 1507,
      "reviewsCount": 0,
      "likesReceivedCount": 201,
      "postsCount": 124,
      "ratingsCount": 289,
      "proExpiresAt": null,
      "title": null,
      "profileCompleted": true,
      "feedCompleted": true,
      "website": null,
      "avatar": {...},
      "coverImage": {...},
      "ratingSystem": "advanced",
      "theme": "light"
    },
    "relationships": {
      "waifu": {
        "links": {
          "self": "https://kitsu.io/api/edge/users/78332/relationships/waifu",
          "related": "https://kitsu.io/api/edge/users/78332/waifu"
        },
        "data": {
          "type": "characters",
          "id": "29496"
        }
      },
      ...
    }
  },
  "included": [
    {
      "id": "29496",
      "type": "characters",
      "links": {
        "self": "https://kitsu.io/api/edge/characters/29496"
      },
      "attributes": {
        "slug": "togame",
        "name": "Togame",
        "malId": 28523,
        ...
      },
      "relationships": {...}
    }
  ]
}

Use in browser

Hi guys,

I've never used npm/node. I would love to use this library for my browser app. Could you give me some hints how I can get this library into pure javascript thats runnable in any browser? Or just pass me some built .js files ;)?

Greetings Florian

Model Composition

Hi

Is it possible to compose models without having to specify them as a JSONAPI relationship?

Thanks

Ben

Pre-compile with Babel for NPM users

screenshot 2016-05-07 10 42 17

Warnings are being thrown when including devour through npm - causing our tests to fail. I don't know much more than that.. 🤓, but we've had to include it as a submodule for now to get around this.

Recursive/Arc Relationships

Hello,
First of all, I thanks for your DEVOUR.
devour json api is a great package, I think. I've seen all approaches in the JavaScript client implementations but jsonapi-datastore and json-api-store are a little useful and the others not.

Finally, I 've determined to use your package DEVOUR.

it works fine so far. but one issue.

In my database, there is "categories" table and it represents both category and subcategory using parent_id field(Arc Model).

and with ruby on rails, I've built JSON API Server.

when hits the url http://192.168.0.124:3003/api/v1/categories?include="sub-categories", it returns as follows. ( "id" : "1", category, in the sub-categories section, it has sub categories information)

{

"data": [
  {
    "id": "1",
    "type": "categories",
    "links": {
      "self": "http://192.168.0.124:3003/api/v1/categories/1"
    },
    "attributes": {
      "name": "Cat1",
      "category-type": 0,
      "sort": 1,
      "deleted": false,
      "created-at": "2017-07-31T10:48:48.000Z",
      "updated-at": "2017-07-31T10:48:50.000Z"
    },
    "relationships": {
      "sub-categories": {
        "links": {
          "self": "http://192.168.0.124:3003/api/v1/categories/1/relationships/sub-categories",
          "related": "http://192.168.0.124:3003/api/v1/categories/1/sub-categories"
        },
        "data": [
          {
            "type": "categories",
            "id": "3"
          },
          {
            "type": "categories",
            "id": "4"
          }
        ]
      },
      "parent": {
        "links": {
          "self": "http://192.168.0.124:3003/api/v1/categories/1/relationships/parent",
          "related": "http://192.168.0.124:3003/api/v1/categories/1/parent"
        }
      },
      "items": {
        "links": {
          "self": "http://192.168.0.124:3003/api/v1/categories/1/relationships/items",
          "related": "http://192.168.0.124:3003/api/v1/categories/1/items"
        }
      }
    }
  },
  {
    "id": "2",
    "type": "categories",
    "links": {
      "self": "http://192.168.0.124:3003/api/v1/categories/2"
    },
    "attributes": {
      "name": "Cat2",
      "category-type": 0,
      "sort": 2,
      "deleted": false,
      "created-at": "2017-07-31T11:21:14.000Z",
      "updated-at": "2017-07-31T11:21:15.000Z"
    },
    "relationships": {
      "sub-categories": {
        "links": {
          "self": "http://192.168.0.124:3003/api/v1/categories/2/relationships/sub-categories",
          "related": "http://192.168.0.124:3003/api/v1/categories/2/sub-categories"
        },
        "data": []
      },
      "parent": {
        "links": {
          "self": "http://192.168.0.124:3003/api/v1/categories/2/relationships/parent",
          "related": "http://192.168.0.124:3003/api/v1/categories/2/parent"
        }
      },
      "items": {
        "links": {
          "self": "http://192.168.0.124:3003/api/v1/categories/2/relationships/items",
          "related": "http://192.168.0.124:3003/api/v1/categories/2/items"
        }
      }
    }
  },
  {
    "id": "3",
    "type": "categories",
    "links": {
      "self": "http://192.168.0.124:3003/api/v1/categories/3"
    },
    "attributes": {
      "name": "Sub Cat1",
      "category-type": 1,
      "sort": 1,
      "deleted": false,
      "created-at": "2017-07-31T11:27:21.000Z",
      "updated-at": "2017-07-31T11:27:22.000Z"
    },
    "relationships": {
      "sub-categories": {
        "links": {
          "self": "http://192.168.0.124:3003/api/v1/categories/3/relationships/sub-categories",
          "related": "http://192.168.0.124:3003/api/v1/categories/3/sub-categories"
        },
        "data": []
      },
      "parent": {
        "links": {
          "self": "http://192.168.0.124:3003/api/v1/categories/3/relationships/parent",
          "related": "http://192.168.0.124:3003/api/v1/categories/3/parent"
        }
      },
      "items": {
        "links": {
          "self": "http://192.168.0.124:3003/api/v1/categories/3/relationships/items",
          "related": "http://192.168.0.124:3003/api/v1/categories/3/items"
        }
      }
    }
  },
  {
    "id": "4",
    "type": "categories",
    "links": {
      "self": "http://192.168.0.124:3003/api/v1/categories/4"
    },
    "attributes": {
      "name": "Sub Cat2",
      "category-type": 1,
      "sort": 1,
      "deleted": false,
      "created-at": "2017-07-31T11:27:54.000Z",
      "updated-at": "2017-07-31T11:27:55.000Z"
    },
    "relationships": {
      "sub-categories": {
        "links": {
          "self": "http://192.168.0.124:3003/api/v1/categories/4/relationships/sub-categories",
          "related": "http://192.168.0.124:3003/api/v1/categories/4/sub-categories"
        },
        "data": []
      },
      "parent": {
        "links": {
          "self": "http://192.168.0.124:3003/api/v1/categories/4/relationships/parent",
          "related": "http://192.168.0.124:3003/api/v1/categories/4/parent"
        }
      },
      "items": {
        "links": {
          "self": "http://192.168.0.124:3003/api/v1/categories/4/relationships/items",
          "related": "http://192.168.0.124:3003/api/v1/categories/4/items"
        }
      }
    }
  }
]

}

and in the client side,

this.jsonApi.define('category',{
  name: '',
  categoryType: '',
  sort: '',
  deleted: '',
  createdAt: '',
  updatedAt: '',
  items:{
    jsonApi: 'hasMany',
    type: 'items'
  },
  subCategories:{
    jsonApi: 'hasMany',
    type: 'categories'
  },
  parent:{
    jsonApi: 'hasOne',
    type: 'category'
  }
})

and when I call below function it returns unexpected results.

this.jsonApi.findAll('category', {include: ['sub-categories']})

[{
  id: '1',
  type: 'categories',
  name: 'Cat1',
  categoryType: 0,
  sort: 1,
  deleted: false,
  createdAt: '2017-07-31T10:48:48.000Z',
  updatedAt: '2017-07-31T10:48:50.000Z',
  subCategories: [],
  parent: null,
  items: [],
  links: { self: 'http://192.168.0.124:3003/api/v1/categories/1' }
},
{
  id: '2',
  type: 'categories',
  name: 'Cat2',
  categoryType: 0,
  sort: 2,
  deleted: false,
  createdAt: '2017-07-31T11:21:14.000Z',
  updatedAt: '2017-07-31T11:21:15.000Z',
  subCategories: [],
  parent: null,
  items: [],
  links: { self: 'http://192.168.0.124:3003/api/v1/categories/2' }
},
{
  id: '3',
  type: 'categories',
  name: 'Sub Cat1',
  categoryType: 1,
  sort: 1,
  deleted: false,
  createdAt: '2017-07-31T11:27:21.000Z',
  updatedAt: '2017-07-31T11:27:22.000Z',
  subCategories: [],
  parent: null,
  items: [],
  links: { self: 'http://192.168.0.124:3003/api/v1/categories/3' }
},
  {
    id: '4',
    type: 'categories',
    name: 'Sub Cat2',
    categoryType: 1,
    sort: 1,
    deleted: false,
    createdAt: '2017-07-31T11:27:54.000Z',
    updatedAt: '2017-07-31T11:27:55.000Z',
    subCategories: [],
    parent: null,
    items: [],
    links: { self: 'http://192.168.0.124:3003/api/v1/categories/4' }
  }]

as you can see, it doesn't take sub categories from server.

what's missing? and wrong?

Hope your help.

Best Regards.

POST to hasMany relationship incorrectly includes empty 'attributes' objects

Per API spec here: http://jsonapi.org/format/#crud-updating-to-many-relationships

hasMany relationships can be bound via a POST action to the relationship URL:

implementation example (this is a sync action which adds all available 'devices' to a 'project')

            addDevicesToProject() {
                this.startEvent();

                return new Promise((resolve, reject) => {
                    //const create = [];

                    const create = this.availableDevices.map((device) => {
                        return {type: 'devices', id: device.id}
                    });
                    JsonApi.one('project', this.project.id).all('device').post(create)
                        .then((responses) => {
                            this.successEvent(responses);
                            console.log('addDevices', responses);
                            resolve(responses);
                        })
                        .catch((error) => {
                            this.errorEvent(error);
                            reject(error);
                        });
                });
            }

In the above, the "create" const is prepared with an array of relationship objects.

The prepared payload is:

{"data":[{"type":"devices","attributes":{},"id":"27"},{"type":"devices","attributes":{},"id":"28"}],"meta":{}}

The 'attributes' fields are unnecessary and cause problems.

I am testing with a version 2.0.3.

Silencing warnings

By looking at the code it seems there is no way of doing this, but I thought I would ask: is there any way of silencing the console statements in the code of this library?

Concrete models and on the fly declaration

Restangular style allows for arbitrary "models" be used in the various calls.

Currently this library requires explicit model definition. Curious about the pros and cons of each.

Relates to #6 and #11

Properties being used on data array

JSON API's responses look like:

{
  data: [...],
  links: {...},
  meta: {...}
}

Devour ends up storing the links and meta information as properties on the data array:

{
  data: [
    ...,
    links: {...},
    meta: {...}
  ]
}

Since storing properties on arrays isn't very conventional I've found it can lead to unpredictable results.

One such instance of this unpredictable behaviour is with Lodash's cloneDeep method, which ends up removing these array properties entirely.

Nested includes

So jsonApi let's you include nested relationships like /author?include=comments,comments.author

Questions can devour accommodate this, and if so how would I define my model? I'd expect something like:

{
  'comments': {
    'type': 'comments',
    'jsonApi': 'hasMany'.
    'author': {
      'type': 'users',
      'jsonApi': 'hasOne'
    }
  }
}

I've tried that but doesn't seem to work, if anyone could shed some light?

thanks

IE && console.log

Some version of IE doesn't like console log when the developer tool isn't open.

I suggest we either use a library that is browser + server compatible OR stub out our own console log.

Devour should have a mechanism for attribute name serialization control

Deserializer converts attribute names from "kebab-case" to camel case when fetching data; on the way back, the serializer does nothing. JSONAPI spec recommends kebab-case, I believe.

So, for example, my API returns { client_id: "1" }, but when asked, devour updates the API with { clientId: "1" }.

Further, there is no way to force devour to send attributes dasherized. E.g. $jsapi.update('matter', { id: "2864", 'client_id': '1'}) will not work.

Deserialize: https://github.com/twg/devour/blob/master/src/middleware/json-api/_deserialize.js#L46
Serialize: https://github.com/twg/devour/blob/master/src/middleware/json-api/_serialize.js#L27

Send empty bodies on GET and DELETE

Since GET and DELETE are not required to have bodies per the JSON API spec, having even an empty JSON object for the body can cause some servers to not respond properly.

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.