{"id":21326217,"url":"https://github.com/masylum/resting-ducks","last_synced_at":"2025-07-12T06:32:58.393Z","repository":{"id":66822764,"uuid":"50933821","full_name":"masylum/resting-ducks","owner":"masylum","description":"REST conventions for single stores","archived":false,"fork":false,"pushed_at":"2020-07-15T20:19:14.000Z","size":25,"stargazers_count":11,"open_issues_count":1,"forks_count":0,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-11-10T10:02:09.277Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/masylum.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-02-02T16:21:19.000Z","updated_at":"2022-03-19T06:50:14.000Z","dependencies_parsed_at":"2023-03-13T20:29:24.435Z","dependency_job_id":null,"html_url":"https://github.com/masylum/resting-ducks","commit_stats":{"total_commits":29,"total_committers":1,"mean_commits":29.0,"dds":0.0,"last_synced_commit":"0fe2cac3ef5e55e6490a3b6048d3608bd0ec753e"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/masylum%2Fresting-ducks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/masylum%2Fresting-ducks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/masylum%2Fresting-ducks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/masylum%2Fresting-ducks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/masylum","download_url":"https://codeload.github.com/masylum/resting-ducks/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225025183,"owners_count":17408994,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-21T21:08:49.401Z","updated_at":"2024-11-21T21:08:50.146Z","avatar_url":"https://github.com/masylum.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Resting Ducks\n\nREST conventions for single tree stores.\n\n[![Build Status](https://travis-ci.org/masylum/resting-ducks.svg?branch=master)](https://travis-ci.org/masylum/resting-ducks)\n\n![](https://media.giphy.com/media/b9QBHfcNpvqDK/giphy.gif)\n\n## Installation\n\n```\nnpm install resting-ducks --save\n```\n\n## Example\n\n```js\nimport { Duck, Api} from 'resting-ducks'\n\nconst client = new Api({host: 'http://localhost:8000', resource: 'tasks'})\nconst tasks = Duck(client, {})('myTasks')\nconst store = createStore(tasks.reducer)\n\nstore.dispatch(\n  task.create({id: 10, name: 'Clean the windows', resolved: false})\n).then(() =\u003e {\n  task.update({resolved: true}, 10, {patch: true})\n})\n```\n\n## Immutable\n\nThe state is stored using [immutable.js](https://facebook.github.io/immutable-js)\n\n## API\n\n### `Duck`\n\nThe constructor accepts two arguments:\n\n  - `client` an API to interact with your server. You can use\n  the one provided by default in `resting-ducks` wich uses [fetch-please](https://github.com/albburtsev/fetch-please)\n  for promise and canceleable requests.\n  - `options`\n    - `indexes` An array of attributes you would like your model indexed by.\n    Defaults to `['id']`\n\n```js\nimport { Duck, Api} from 'resting-ducks'\n\nconst client = new Api({host: 'http://localhost:8000', resource: 'tasks'})\nconst tasks = Duck(client, {\n  indexes: ['id', 'project_id']\n})('myTasks')\nconst store = createStore(tasks.reducer)\n```\n\n### `Api`\n\nDefines how you interact with your server.\nMust implement `fetch`, `post`, `put`, and `del`.\n\nOptions:\n\n  - `host` Mandatory. The host of your server\n  - `resource` Mandatory. The name of your resource\n  - `base` Defaults to `/`. The prefix (for instance versioning) of your API\n\n```js\nimport { Api } from 'resting-ducks'\n\nconst client = new Api({\n  host: 'http://localhost:3000',\n  resource: 'users',\n  base: '/v2'\n})\n\nconst {xhr, promise} = client.fetch()\n\npromise.then((data) =\u003e {\n  console.log(data)\n})\n\n// Timeout of 500ms\nsetTimeout(() =\u003e {\n  xhr.abort()\n}, 500)\n```\n\n### `Duck API`\n\n**Resting ducks** come with all the common *REST* actions so you don't\nhave to re-implement them over and over in your stores.\n\n### Reducer\n\n##### `reducer(state, action)`\n\nThe reducer for your resource. Add this one to your store and you are all set!\n\n### Actions creators\n\n##### `set(resources, id|cid = null)`\n\nReplace the current resources with the given ones.\n\nIf a `id`/`cid` is given, it applies only to the given resource\n\n##### `patch(attributes, id|cid)`\n\nPatch the resource with the given attributes.\n\n##### `request({label, xhr}, id|cid = null)`\n\nMarks the current duck as having an\nongoing cancelable request. You can use this to represent a loading\ntransaction and cancel it if needed.\n\nIf a `id`/`cid` is given, it applies only to the given resource\n\n##### `error({label, error}, id|cid = null)`\n\nMarks the current duck as having an\nerror. You can use this to represent it.\n\nIf a `id`/`cid` is given, it applies only to the given resource.\n\n##### `add(attributes)`\n\nAppend a new resource on the duck.\n\n##### `remove(id|cid)`\n\nRemove a resource.\n\n##### `fetch()`\n\nRetrieve your models from your server.\n\nIt marks the `request` object so you can track progress and cancel\nit if needed.\n\nIn case of error it marks the `error` object.\n\n##### `create(attributes, options)`\n\nSend a new resource to your server. The new resource\nis optimistically added on the client.\n\nIt marks the `request` object so you can track progress and cancel\nit if needed.\n\nIn case of error it marks the `error` object.\n\n##### `udpate(attributes, id, options)`\n\nSend new attributes for your resource to your server.\nThe new attributes are optimistically set on the client.\n\nIt marks the `request` object so you can track progress and cancel\nit if needed.\n\nIn case of error it marks the `error` object.\n\nExtra options:\n\n  - `patch`: Wether the attributes are a patch or a full representation\n  of the resource. Defaults to false.\n\n`TODO` Add support for `PATCH`\n\n##### `destroy(id, options)`\n\nDestroy a resource on your server. The resource is optimistically\nremoved on the client.\n\nIt marks the `request` object so you can track progress and cancel\nit if needed.\n\nIn case of error it marks the `error` object.\n\n### Options\n\n`create`, `update` and `destroy` are optimistic by default. You can\ndisable that behaviour passing the `optimistic` flag to `false`.\n\n## Tree schema\n\nYour tree will have the following schema:\n\n```js\nresources: [\n  {                    // Information at the resource level\n    cid: String,       // Client side id. Used for optimistic updates\n    request: {         // An ongoing request\n      label: String,   // Examples: 'updating', 'creating', 'fetching', 'destroying' ...\n      xhr: Object,     // The xhr object. You can abort it with `xhr.abort()`\n    },\n    error: {           // A failed request\n      label: String,   // Examples: 'updating', 'creating', 'fetching', 'destroying' ...\n      error: String,   // A string representing the error\n    },\n    attributes: Object // The resource attributes\n  }\n]                      // Information at the collection level\ncid: String,           // The latest Client id generated\nrequest: {             // An ongoing request\n  label: String,       // Examples: 'updating', 'creating', 'fetching', 'destroying' ...\n  xhr: Object,         // The xhr object. You can abort it with `xhr.abort()`\n},\nerror: {               // A failed request\n  label: String,       // Examples: 'updating', 'creating', 'fetching', 'destroying' ...\n  error: Object,       // A string representing the error\n}\n```\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2016 Pau Ramon \u003cmasylum@gmail.com\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmasylum%2Fresting-ducks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmasylum%2Fresting-ducks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmasylum%2Fresting-ducks/lists"}