{"_id":"@borisp/vuex-rest-api","_rev":"1-82073b2edecce6924bd3f8044e27b2cf","name":"@borisp/vuex-rest-api","dist-tags":{"latest":"2.8.0"},"versions":{"2.8.0":{"name":"@borisp/vuex-rest-api","version":"2.8.0","description":"A helper utility to simplify the usage of REST APIs with Vuex. Based on axios.","author":{"name":"Christian Malek"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/christianmalek/vuex-rest-api.git"},"dependencies":{"lodash.clonedeep":"4.5.x"},"peerDependencies":{"axios":"0.18.x"},"scripts":{"build":"tsc -p ."},"devDependencies":{"typescript":"2.7.x"},"files":["dist","README.md"],"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"9db40314c4f99ae57e6d654b0deeec87c68b6231","bugs":{"url":"https://github.com/christianmalek/vuex-rest-api/issues"},"homepage":"https://github.com/christianmalek/vuex-rest-api#readme","_id":"@borisp/vuex-rest-api@2.8.0","_npmVersion":"6.1.0","_nodeVersion":"10.6.0","_npmUser":{"name":"borisp","email":"boris.polak@icloud.com"},"dist":{"integrity":"sha512-5uW0nq76r7T1SWc/lVpPjiVMcQ6bg3T1HQEqS/tNKH36Bfv7ifFG4VSUDh4n9UnbWdjoDdvvIbzDnmNEGhCrEQ==","shasum":"286e7f7f0e962e026b3a77305af9e476e75b84ff","tarball":"https://registry.npmjs.org/@borisp/vuex-rest-api/-/vuex-rest-api-2.8.0.tgz","fileCount":10,"unpackedSize":38054,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJba0RICRA9TVsSAnZWagAAwyUP/2IqObQGWZFHu3P0sUWM\narU3+AkAaH6EVjTOQiKW0pD3gTRnRUXdPGBB0zL5XMzpfzS15iYf2sc+nZkl\nQzoz24iMIeLDBzo0xy+gJpwpT3dbRmAWgFd8gJ+XSVRmqGxBwr4p4sxthHRr\nOP5xy2Qvw1d5jgo6n0u2o2oz9zYg7LOqzrcI5j1brmqBmTsUhfDSfN713XxL\nhIG1z9+2T1BYTnDlL+zhUw9KrqdiPVadeUWtBK6wmVWUULNlYz7YPdmgT6nB\nPovPiGkftK64XtTav021BFpiiQUD3X5Pkfm3j1m/JpcuP3E+RTc+3cNLCDhf\nSbbxwT9YyTrEH+HR7aM3cC5XBwjtCA7vNBgecfqcF/9xifkGE1yVipgXBpHL\nwYZ208ruTwAjnerjzIno+fTMkuClwchx1tefCVTq0qFNpOguv09mIIcErntf\nLTSRir1gD7GX9a2Y+s2UTE7RaHQn6To94XRZTBvrpZvNqaNH9Au80vEk9VU0\ngnvk+LVtP77ZHzHgqplk/T2ecHu6wTK1y+z4jf1nc+Xjdh8VFdLROwJ7Yt24\nqvOAeSDo5qwyWuAK7xKcmDpw61FkCVdVYcYNnGiPulEU9BaJr18BMNuRfRSA\nazmP05iwBr37Co/u3pMrCJh8lQbhIWkOrSWO55/o5J/vlAe/egNgtqeUQjw+\nTzR1\r\n=oYvX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGVlY1MI/CV/u7G+IxeR7D6TZeL+Um/VjAZTspgc+pfgAiEA74p7T3fJZqgnzfXUMlj2g1mzNaTSBGhK8F2Ya/XesBk="}]},"maintainers":[{"name":"borisp","email":"boris.polak@icloud.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/vuex-rest-api_2.8.0_1533756488769_0.7203221858518174"},"_hasShrinkwrap":false}},"time":{"created":"2018-08-08T19:28:08.475Z","2.8.0":"2018-08-08T19:28:08.846Z","modified":"2022-04-04T20:12:52.692Z"},"maintainers":[{"name":"borisp","email":"boris.polak@icloud.com"}],"description":"A helper utility to simplify the usage of REST APIs with Vuex. Based on axios.","homepage":"https://github.com/christianmalek/vuex-rest-api#readme","repository":{"type":"git","url":"git+https://github.com/christianmalek/vuex-rest-api.git"},"author":{"name":"Christian Malek"},"bugs":{"url":"https://github.com/christianmalek/vuex-rest-api/issues"},"license":"MIT","readme":"# vuex-rest-api\n\n[![](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/vuejs/awesome-vue)\n[![](https://img.shields.io/badge/vuex-2.x-brightgreen.svg)](https://vuejs.org)\n[![npm](https://img.shields.io/npm/v/vuex-rest-api.svg)](https://www.npmjs.com/package/vuex-rest-api)\n[![npm](https://img.shields.io/npm/dm/vuex-rest-api.svg)](https://www.npmjs.com/package/vuex-rest-api)\n\nA Helper utility to simplify the usage of REST APIs with Vuex 2. Uses the popular HTTP client [axios](https://github.com/mzabriskie/axios) for requests. [Works](#usage-with-websanovavue-auth) with [websanova/vue-auth](https://github.com/websanova/vue-auth).\n\n## Table of Contents\n\n* [What is this good for](#what-is-this-good-for)\n* [Installation](#installation)\n* [Steps](#steps)\n* [API](#api)\n    * [constructor(options:Object):Vapi](#constructoroptionsobjectvapi)\n    * [add(options):Vapi](#addoptionsvapi)\n    * [getStore(options):Object](#getstoreoptionsobject)\n* [Miscellaneous](#miscellaneous)\n  * [Calling the actions](#calling-the-actions)\n  * [Query params](#query-params)\n  * [Add additional state, actions and mutations to the store](#add-additional-state-actions-and-mutations-to-the-store)\n  * [Usage with websanova/vue\\-auth](#usage-with-websanovavue-auth)\n  * [Check error and loading state of requests](#check-error-and-loading-state-of-requests)\n  * [Changelog](#changelog)\n\n## What is this good for\nIf you want to connect a REST API with Vuex you'll find that there are a few repetitive steps. You need to request the data from the api (with an action) and set the state (via a mutation). This utility (for the sake of brevity called `Vapi` in the README) helps in *creating the store* by setting up the state, mutations and actions with a easy to follow pattern.\n\n## It is **not** a middleware.\nIt's just a helper utility to help prepraring the store object for you. If there's something you don't like just overwrite the property.\n\n## Installation\n```bash\nnpm install vuex-rest-api\n```\n\n> Some notes: This readme assumes that you're using at least ES2015.\n\n## Steps\n1. Import `vuex-rest-api` (I called it `Vapi`).\n1. Create a `Vapi` instance.  \n   At least you have to set the base URL of the API you're requesting from. You can also define the default state. If you don't define a default state from a property it will default to `null`.\n   In the example\n1. Create the actions.  \n   Each action represents a Vuex action. If it will be called (property `action`), it requests a specific API endpoint (property `path`) and sets the related property named `property` to the response's payload.\n1. Create the store object\n1. Pass it to Vuex. Continue reading [here](#calling-the-actions) to know how to *call the actions*.\n\n```js\n// store.js\n\nimport Vuex from \"vuex\"\nimport Vue from \"vue\"\n// Step 1\nimport Vapi from \"vuex-rest-api\"\n\nVue.use(Vuex)\n\n// Step 2\nconst posts = new Vapi({\n  baseURL: \"https://jsonplaceholder.typicode.com\",\n    state: {\n      posts: []\n    }\n  })\n  // Step 3\n  .get({\n    action: \"getPost\",\n    property: \"post\",\n    path: ({ id }) => `/posts/${id}`\n  })\n  .get({\n    action: \"listPosts\",\n    property: \"posts\",\n    path: \"/posts\"\n  })\n  .post({\n    action: \"updatePost\",\n    property: \"post\",\n    path: ({ id }) => `/posts/${id}`\n  })\n  // Step 4\n  .getStore()\n\n// Step 5\nexport const store = new Vuex.Store(posts)\n```\n\n\n\n## API\nThe following sections explain the API of the `Vapi` class.\n\n### `constructor(options:Object):Vapi`\n\nCreates a new `Vapi` instance and returns it.\n\n```js\nconst vapi = new Vapi(options)\n```\n\nThe parameter `options` consists of the following properties:\n\n#### `# axios`\n- **Type**: `axios` (instance)  \n- **Default**: `axios` (instance)  \n- **Usage**: The axios instance to use for the requests. This is pretty useful if you use a package like websanova/vue-auth which sets automatically the Authorization header. So you don't need to care. If you don't pass an instance, it will use the global axios instance.  \n\n#### `# baseURL`\n- **Type**: `string`\n- **Usage**: The API's base URL without a specific endpoint's path. It's usage is optional. If you don't set it, it will use the base URL of the axios instance. Please note that `baseURL` has a higher priority than the baseURL set in the passed axios instance. You can also set base URL in the request config when you add an action. The priority is as following:\n\n  `baseURL > axios instance base URL > request config base URL`\n```js\n{\n  baseURL: \"https://jsonplaceholder.typicode.com\"\n}\n```\n\n#### `# queryParams`  \n- **Type**: `boolean` \n- **Default**: If you don't set a property's default value the value is `null`.  \n- **Usage**: If you want to append the params to the request URL, set this property to true. You can also set this option in every action you need it if you don't need it for every action.\n```js\n{\n  queryParams: true\n}\n```\n\n#### `# state`\n- **Type**: `Object`\n- **Default**: Every property will default to `null`.\n- **Usage**: The default state of your properties.  \n```js\n{\n  state: {\n    post: null, // this is unnecessary (default is null)\n    posts: []\n  }\n}\n```\nSets post to `null` and posts to an empty array.\n\n### `add(options):Vapi`\n\nAdds an action to access an API endpoint and returns the `Vapi` instance.\n\nThe parameter `options` consists of the following properties:\n\n#### `# action` (required)\n- **Type**: `string`  \n- **Usage**: The name of the action.\n```js\n{\n  action: \"getPosts\"\n}\n```\n\n#### `# method`\n- **Type**: `string`  \n- **Default**: `\"get\"`  \n- **Usage**: The HTTP method to request the API. Following HTTP Methods are allowed at the moment:\n  - get\n  - delete\n  - head\n  - post\n  - put\n  - patch\n\n```js\n{\n  method: \"get\"\n}\n```\n\n##### shorthand syntax\nYou can also use the http method instead of `add` to omit to set the `options.method` like this. This works with get, delete, post, put and patch:\n```js\n// regular way\nvrap.add({\n  method: \"delete\"\n  // other options...  \n})\n\n//shorthand\nvrap.delete({\n  // other options...\n})\n```\n\n#### `# property`\n- **Type**: `string`\n- **Default**: `null`\n- **Usage**: The property of the state which should be automatically changed if the resolve is successfully.\n```js\n{\n  property: \"posts\"\n}\n```\n\n##### When to set `property` in spite of it's optionality\nSometimes you have to set the state by yourself. In that case you may consider to avoid setting `property`. Please consider the following consequences:\n\n- `state.pending.<property name>` and `state.error.<property name>` won't be set. So you **can't** check these properties to see if the request is still pending or failed. Nevertheless you can still set the `onError` property to react to the error case.\n- Because the property's name is unknown *vuex-rest-api* can't set the initial state for this property. You have to set the initial state by yourself.\n- In the case of successful requests there will be nothing done with the payload. You have to set the `onSuccess` method to set the state (with the payload) by yourself.\n\n#### `# path` (required)\n- **Type**: `Function|string`  \n- **Usage**: This property can either be a function or a path describing the rest of the API address (without the base URL).\n\n##### Usage with a function\nHere we pass a custom path function. This is necessary, because we also need to pass an id. Please note that *id* is passed in an object. This is necessary because you could pass multiple arguments.\n```js\n{\n  path: ({id}) => `/post/${id}`\n}\n```\n\n##### Usage with a string\nMaybe the API endpoint needs no parameters. Then you can use a string like this:\n```js\n{\n  path: \"/posts\"\n}\n```\n\n#### `# headers`\n- **Type**: `Function|Object`  \n- **Usage**: This property allows to provide dynamic headers for every request. It can either be a function or an object.\n\n##### Usage with a function\nHere we pass a custom headers function. This allows us to change the extra headers for each request. The data has to be passed over the `params` bag.\n\n> Please note that headers provided via this property will override it's counterpart you maybe set via `requestConfig.headers`.\n\n```js\n// setting the header\n{\n  headers: ({foo, bar}) => ({\n      \"FOO\": foo,\n      \"BAR\": bar\n    })\n}\n\n// calling the mapped action and passing the data over the params object\nthis.getPosts({\n  params: { \n    foo: \"foo-header\",\n    bar: \"bar-header\"\n  } \n})\n```\n\n##### Usage with a string\nIf the headers don't have to be evaluted on every request, just pass them via an object. Alternatively you could also set the headers via the `requestConfig.headers` property.\n```js\n{\n  headers: {\n    \"FOO\": \"foo-header\",\n    \"BAR\": \"bar-header\"\n  }\n}\n```\n\n#### `# beforeRequest`\n- **Type**: `Function`  \n- **Default**: `undefined`  \n- **Usage**: This function will be called before resolving the action, so you can update state optimistically.\n```js\n{\n  beforeRequest: (state, { params, data }) => {\n    state.posts = state.posts.filter(post => post.id !== params.id)\n  }\n}\n```\n\n#### `# onSuccess`\n- **Type**: `Function`\n- **Default**: `undefined`\n- **Usage**: This function will be called after successfully resolving the action. If you define this property, only the corresponding pending and error properties will be set, but not `state[property]`.\n```js\n{\n  onSuccess: (state, payload, axios) => {\n    // if you set the onSuccess function you have to set the state manually\n    state.posts = payload.data\n    state.post = payload.data[0]\n  }\n}\n```\n\n#### `# onError`\n- **Type**: `Function`  \n- **Default**: `undefined`  \n- **Usage**: This function will be called if the action request fails. If you define this property, only the corresponding `pending` and `error` properties of the set `property` will be set, but not `state[property]`.\n```js\n{\n  onError: (state, error, axios) => {\n    Toast.showError(`Oops, there was following error: ${error}`)\n\n    // if you set the onError function you have to set the state manually\n    state.post = null\n  }\n}\n```\n\n#### `# requestConfig`\n- **Type**: `Object`  \n- **Default**: `{}`  \n- **Usage**: An [`axios.requestConfig`](https://github.com/mzabriskie/axios#request-config) object. Please note that the passed HTTP method (see `options.method` above) won't be changed.\n```js\n{\n  requestConfig: {\n    //excerpt from (https://github.com/mzabriskie/axios#request-config)\n    // `paramsSerializer` is an optional function in charge of serializing `params`\n    // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)\n    paramsSerializer: function(params) {\n      return Qs.stringify(params, {arrayFormat: 'brackets'})\n    },\n  }\n}\n```\n\n#### `# queryParams`\n- **Type**: `boolean`  \n- **Default**: `undefined`  \n- **Usage**: If you want to append the params to the request URL, set this property to true.\n```js\n{\n  queryParams: true\n}\n```\n\n### `getStore(options):Object`\n\nCreates an object you can pass to Vuex to add a store.\n\nThe parameter `options` consists of the following properties:\n\n#### `# createStateFn`\n- **Type**: `boolean`  \n- **Default**: `false`\n- **Usage**: Decides if the state should be returned as a function or an object. This option has to be changed if you want to share the state of your created store. Read chapter *module reuse* in the [Vuex documentation](https://vuex.vuejs.org/en/modules.html) for more details.\n```js\n{\n  createStateFn: false\n}\n```\n\nThe returned object looks like this if you would call it with the settings of the example:\n```js\n{\n  state: {\n    pending: {\n      posts: false,\n      post:  false\n    },\n    error: {\n      posts: null,\n      post:  null\n    },\n    posts:   [],\n    post:    null\n  }),\n  mutations: {\n    LIST_POSTS:            Function,\n    LIST_POSTS_SUCCEEDED:  Function,\n    LIST_POSTS_FAILED:     Function,\n    GET_POST:              Function,\n    GET_POST_SUCCEEDED:    Function,\n    GET_POST_FAILED:       Function,\n    UPDATE_POST:           Function,\n    UPDATE_POST_SUCCEEDED: Function,\n    UPDATE_POST_FAILED:    Function\n  },\n\n  //every action's signatures is function(params, data)\n  actions: {\n    listPosts:  Function,\n    getPost:    Function,\n    updatePost: Function\n  }\n}\n```\n\nAs you can see, it just created the store for us. No more, no less.\n\n## Miscellaneous\n\n### Calling the actions\n\nPlease respect the following function signature if you want to call an action:\n```js\n// direct via store\nthis.$store.dispatch(\"actionName\", { params: {}, data: {} })\n\n// or with mapActions\nthis.actionName({ params: {}, data: {} })`\n```\n\n`params` (optional) represents the data you passed to the `path` property.\n`data` (optional) is your request's payload.\n\nPlease note that you **do not** have to set params, data or the enclosing object if you don't need them.\n\nExamples:\n- If you want to request all posts with the action `listPosts` and don't have any data or params, you could call it like this:\n\n```js\n// direct via store\nthis.$store.dispatch(\"listPosts\")\n\n// or with mapActions\nthis.listPosts()\n```\n\n\n- If you want to fetch a specific post with an parameter named *id* call one of the following:\n```js\n// direct via store\nconst params = { id: 42 }\nthis.$store.dispatch(\"getPost\", { params })\n\n// or with mapActions\nthis.getPost({ params })\n```\n  \n- If you have an action where you have data and params to set, just do it like this:\n```js\n// direct via store\nconst params = { id: 42 }\nconst data = { content: \"foobar\" }\nthis.$store.dispatch(\"actionName\", { params, data })\n\n// or with mapActions\nthis.actionName({ params, data })\n```\n\n### Query params\nIf you want to use query params just set the `queryParams` property either in the constructor or the options from the add method. If you need it for just one action set it in the corresponding method. On the other hand, if you need it for all actions, set it in the constructor.\n\nPlease note that the method's `queryParams` property is *more specific* than the constructor's. So if you set `queryParams` in a method's options it will override the `queryParams` value of the constructor option!\n\nParams will also be appended to the URL if you set a `paramsSerializer` function in the `requestConfig` property of the `add` method or if you pass an axios instance with set `paramsSerializer` function in the Resource constructor.\n\n### Add additional state, actions and mutations to the store\nAs mentioned before, *vuex-rest-api* is just creating a regular store object. So you can add arbitrary actions, mutations and state properties to the store as written in the [Vuex documentation](https://vuex.vuejs.org/en/core-concepts.html):\n\n```js\n// resource creation hidden for the sake of brevity\n\n// create the store\nposts = postsResource.getStore()\n\n// add a simple counter to the store\nposts.state.counter = 0\nposts.mutations.increment = state => {\n  state.counter++\n}\nposts.actions.increment = context => {\n  context.commit(\"increment\")\n}\n```\n\n### Usage with websanova/vue-auth\n\nIf you want to use this little helper with vue-auth you don't have to do anything. It will just work due to the fact that vue-auth uses the global axios instance. Don't pass any axios instance to Vapi and it will work.\n\n### Check error and loading state of requests\n`vuex-rest-api` sets for every property set in the `add()` method two different states:\n\n- `state.pending.<propertyName>` (`true` when loading, otherwise `false`)\n- `state.error.<propertyName>` (`null` if there's no error, otherwise it contains the error object)\n\nThis is really handy if you want to show a loading hint for specific requests or an error message:\n\n```js\n<template>\n  <div>\n    <ul>\n      <li v-for=\"post in posts\">{{post}}</li>\n    </ul>\n    <p v-if=\"pending.posts\">loading posts...</p>\n    <p v-if=\"error.posts\">loading failed</p>\n  </div>\n</template>\n\n<script>\nimport { mapState, mapActions } from 'vuex'\n\nexport default {\n  created() {\n    this.getPosts()\n  },\n\n  // make states available\n  computed: mapState({\n    posts: state => state.posts.posts,\n    pending: state => state.pending,\n    error: state => state.error\n  }),\n  methods: {\n    ...mapActions([\n      \"getPosts\"\n    ])\n  }\n}\n</script>\n```\n\n### Changelog\nsee [CHANGELOG.md](CHANGELOG.md)\n","readmeFilename":"README.md"}