flarum / issue-archive

0 stars 0 forks source link

Extract JavaScript data layer (Store and Model) into external package #344

Open tobyzerner opened 8 years ago

tobyzerner commented 8 years ago

Part of flarum/framework#262.

Would be called tobscure/json-api-client or something.

Proposal for a refined API:

import { Store, Model } from 'json-api-client';

// We would define a custom adapter as part of Flarum to handle AJAX requests.
// Adapters must simply implement `request(method, url, data)`
const store = new Store({
  request(method, url, data) {
    return app.request({
      method: method,
      url: baseUrl + url,
      data: data
    });
  }
});

// Load a preloaded JSON-API document into the store.
store.sync({
  data: {
    type: 'posts',
    id: '456',
    attributes: {
      content: 'world'
    }
  }
});

// Push a preloaded resource into the store.
store.push({
  type: 'discussions',
  id: '123',
  attributes: {
    title: 'hello',
    commentsCount: 1
  },
  relationships: {
    posts: {
      data: [
        {type: 'posts', id: '456'}
      ]
    },
    startUser: {
      data: {type: 'users', id: '789'}
    }
  }
});

// Now retrieve it locally. (find returns null if the record isn't already
// loaded.) Find by ID by default, but allow finding by other fields too.
const discussion = store.find('discussions', '123');
const discussion = store.find('discussions', 'title', 'hello');

// discussion is a Model instance, which is set up so that all the attributes
// and relationships present in the resource are accessible via getters.
console.log(discussion.id); // "123"
console.log(discussion.type); // "discussions"
console.log(discussion.title); // "hello"
console.log(discussion.posts[0].content); // "world"

// Optionally define Model subclasses for the Store to use, so we can specify
// date fields and add custom computed attributes.
class Discussion extends Model {
  static dates() {
    return ['startTime', 'lastTime'];
  }

  get repliesCount() {
    return Math.max(0, this.commentsCount - 1);
  }
}

store.model('discussions', Discussion);

const discussion = store.find('discussions', '123');
console.log(discussion.startTime); // Date object
console.log(discussion.repliesCount); // 0

// Remove the given discussion from the local store.
store.unload(discussion);

// Can also fetch an array of all loaded records of any given type.
const discussions = store.all('discussions');

// Load a discussion into the store by querying the JSON-API. Returns an A+ Promise.
store.load('discussions', '123').then(discussion => console.log(discussion));

// Save attributes and relationships for a model.
store.save(discussion, attributes, relationships);

// Delete a model.
store.delete(discussion);

// Create a new model.
store.create('discussions', attributes, relationships);

Thoughts?

franzliedke commented 8 years ago

Makes sense. Any big changes compared to the current API?

And is this connected to Mithril at all?

tobyzerner commented 8 years ago

The relevant changes from the current API are:

I think that's all.

Nope this isn't related to Mithril, it's framework agnostic :)

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. We do this to keep the amount of open issues to a manageable minimum. In any case, thanks for taking an interest in this software and contributing by opening the issue in the first place!