├── .babelrc ├── .clintonrc.json ├── .editorconfig ├── .github ├── funding.yml └── workflows │ └── nodejs.yml ├── .gitignore ├── .huskyrc ├── .npmignore ├── .nycrc ├── ava.config.js ├── changelog.md ├── license ├── package-lock.json ├── package.json ├── readme.md ├── src └── index.js ├── test ├── snapshots │ ├── test-core.js.md │ └── test-core.js.snap ├── test-core.js ├── test-mutate.js └── test-query.js └── xo.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": 10 8 | } 9 | } 10 | ], 11 | [ 12 | "minify", 13 | { 14 | "removeUndefined": false, 15 | "mangle": false 16 | } 17 | ] 18 | ], 19 | "plugins": [ 20 | "add-module-exports" 21 | ] 22 | } -------------------------------------------------------------------------------- /.clintonrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignores": [ 3 | "test/**", 4 | "tmp/**", 5 | "lib/**", 6 | "dist/**", 7 | "docs/**", 8 | "src/docs/**", 9 | "*.{html,jpg}" 10 | ], 11 | "rules": { 12 | "pkg-main": "off", 13 | "xo": "off", 14 | "use-travis": "off", 15 | "ava": "off", 16 | "no-callback": "off" 17 | } 18 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | quote_type = single 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [{package.json,*.yml,*.jade,*.pss,*.css,*.js,*.md,.*,*.ts}] 13 | indent_size = 2 14 | 15 | [{changelog.md,.*}] 16 | insert_final_newline = false 17 | 18 | [*.md] 19 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.github/funding.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # scrums 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://paypal.me/scrumpay'] 13 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Actions Status 2 | on: 3 | pull_request: 4 | types: [opened, synchronize] 5 | branches: 6 | - master 7 | env: 8 | CI: true 9 | 10 | jobs: 11 | run: 12 | name: Node ${{ matrix.node }} on ${{ matrix.os }} 13 | runs-on: ${{ matrix.os }} 14 | 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | node: [10, 12, 14] 19 | os: [ubuntu-latest] 20 | 21 | steps: 22 | - name: Clone repository 23 | uses: actions/checkout@v2 24 | 25 | - name: Set Node.js version 26 | uses: actions/setup-node@v1 27 | with: 28 | node-version: ${{ matrix.node }} 29 | 30 | - name: Install npm dependencies 31 | run: npm ci 32 | 33 | - name: Run tests 34 | run: npm run test 35 | 36 | - name: Run Coveralls 37 | uses: coverallsapp/github-action@master 38 | with: 39 | github-token: "${{ secrets.GITHUB_TOKEN }}" 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | coverage 4 | .nyc_output 5 | npm-debug.log 6 | tmp -------------------------------------------------------------------------------- /.huskyrc: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-push": "npm t", 4 | "commit-msg": "commitlint --extends=@commitlint/config-angular -e" 5 | } 6 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | src 3 | .gitignore 4 | .travis.yml 5 | coverage 6 | .nyc_output -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "reporter": ["lcov", "text"], 3 | "extension": [".js"] 4 | } -------------------------------------------------------------------------------- /ava.config.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | require: [ 3 | '@babel/register' 4 | ], 5 | verbose: true 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | ## 0.1.0 (2020-09-25) 2 | 3 | * feat: init project ([385a35d](https://github.com/Scrum/vue-axillo/commit/385a35d)) 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Ivan Demidov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-axillo", 3 | "version": "0.1.0", 4 | "description": "Composable Axios for REST API with query notation GraphQL", 5 | "license": "MIT", 6 | "repository": "Scrum/vue-axillo", 7 | "bugs": "Scrum/vue-axillo/issues", 8 | "author": { 9 | "name": "Ivan Demidov", 10 | "email": "Scrum@list.ru", 11 | "url": "https://twitter.com/Scrum_" 12 | }, 13 | "main": "lib/index.js", 14 | "engines": { 15 | "node": ">=10" 16 | }, 17 | "scripts": { 18 | "version": "conventional-changelog -i changelog.md -s -r 0 && git add changelog.md && git commit -m \"build: update changelog\"", 19 | "prepare": "npm run build", 20 | "build": "rimraf lib && babel src -d lib", 21 | "test": "xo && nyc ava", 22 | "pretest": "clinton" 23 | }, 24 | "files": [ 25 | "lib/" 26 | ], 27 | "keywords": [ 28 | "vue", 29 | "axios", 30 | "rest", 31 | "api", 32 | "graphql", 33 | "composable" 34 | ], 35 | "dependencies": { 36 | "axios": "^0.20.0", 37 | "rexios": "0.0.1" 38 | }, 39 | "devDependencies": { 40 | "@babel/cli": "^7.7.0", 41 | "@babel/core": "^7.11.6", 42 | "@babel/preset-env": "^7.7.1", 43 | "@babel/register": "^7.7.0", 44 | "@commitlint/cli": "^11.0.0", 45 | "@commitlint/config-angular": "^11.0.0", 46 | "ava": "^3.12.1", 47 | "babel-plugin-add-module-exports": "^1.0.4", 48 | "babel-preset-minify": "^0.5.1", 49 | "clinton": "^0.14.0", 50 | "conventional-changelog-cli": "^2.1.0", 51 | "husky": "^4.3.0", 52 | "nyc": "^15.1.0", 53 | "rimraf": "^3.0.0", 54 | "vue": "^3.0.0", 55 | "xo": "^0.33.1" 56 | }, 57 | "peerDependencies": { 58 | "vue": ">=3.0.0" 59 | }, 60 | "funding": { 61 | "type": "patreon", 62 | "url": "https://patreon.com/scrums" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # vue-axillo 2 | > Composable [Axios](https://github.com/axios/axios) for [REST](https://en.wikipedia.org/wiki/Representational_state_transfer) API with query notation [GraphQL](https://graphql.org/) 3 | 4 | [![Actions Status](https://github.com/Scrum/vue-axillo/workflows/Actions%20Status/badge.svg?style=flat-square)](https://github.com/Scrum/vue-axillo/actions?query=workflow%3A%22CI+tests%22)[![node](https://img.shields.io/node/v/vue-axillo.svg?style=flat-square)]()[![npm version](https://img.shields.io/npm/v/vue-axillo.svg?style=flat-square)](https://www.npmjs.com/package/vue-axillo)[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg?style=flat-square)](https://github.com/xojs/xo)[![Coveralls status](https://img.shields.io/coveralls/Scrum/vue-axillo.svg?style=flat-square)](https://coveralls.io/r/Scrum/vue-axillo) 5 | 6 | [![npm downloads](https://img.shields.io/npm/dm/vue-axillo.svg?style=flat-square)](https://www.npmjs.com/package/vue-axillo)[![npm](https://img.shields.io/npm/dt/vue-axillo.svg?style=flat-square)](https://www.npmjs.com/package/vue-axillo) 7 | 8 | ## Why? 9 | Axillo is a set of tools effort to help you use [REST](https://en.wikipedia.org/wiki/Representational_state_transfer) API in your apps. It's well known for its client and its server. 10 | 11 | All queries use [rexios](https://github.com/Scrum/rexios) utils normalize url, data, params for axios when using [REST](https://en.wikipedia.org/wiki/Representational_state_transfer) API request 12 | 13 | ## Install 14 | 15 | ```bash 16 | $ npm install vue-axillo 17 | ``` 18 | 19 | > **Note:** This project is compatible with node v10+ 20 | 21 | ## Usage 22 | 23 | ### Query 24 | 25 | > For `query` requests the `get` method is used by default 26 | 27 | ```js 28 | import axillo from 'vue-axillo'; 29 | 30 | export default { 31 | setup() { 32 | const { 33 | query, // query method 34 | loading, // request status 35 | result: users // reactive data 36 | } = axillo({ 37 | baseURL: 'v2/api/user/' 38 | }); 39 | 40 | async function submit() { 41 | await query(/* params */); // => request on 'v2/api/user/' 42 | } 43 | 44 | return { 45 | submit, 46 | loading, 47 | users, 48 | } 49 | } 50 | } 51 | ``` 52 | 53 | ### Query with params 54 | ```js 55 | import axillo from 'vue-axillo'; 56 | 57 | export default { 58 | setup() { 59 | const { 60 | query, // query method 61 | loading, // request status 62 | result: users // reactive data 63 | } = axillo({ 64 | baseURL: 'v2/api/user/' 65 | }); 66 | 67 | async function submit() { 68 | await query({ 69 | id: 123, 70 | article: 1, 71 | }); // => request on 'v2/api/user/123/?article=1' 72 | } 73 | 74 | return { 75 | submit, 76 | loading, 77 | users, 78 | } 79 | } 80 | } 81 | ``` 82 | 83 | ### Query with reactive params 84 | ```js 85 | import axillo from 'vue-axillo'; 86 | import { ref, watch } from 'vue' // vue 3 or composition-api 87 | 88 | export default { 89 | setup() { 90 | const name = ref(null); 91 | const { 92 | params: searchByName, // params for query 93 | loading, // request status 94 | result: users // reactive data 95 | } = axillo({ 96 | baseURL: 'v2/api/user/' 97 | }); 98 | 99 | watch(name, value => { 100 | searchByName.value = value; 101 | }); 102 | 103 | return { 104 | loading, 105 | users, 106 | } 107 | } 108 | } 109 | ``` 110 | 111 | ### Mutate 112 | 113 | > For `mutate` requests the `post` method is used by default 114 | 115 | ```js 116 | import axillo from 'vue-axillo'; 117 | 118 | export default { 119 | setup() { 120 | const { 121 | mutate, // mutate method 122 | loading, // request status 123 | onDone, // suceess callback 124 | onError, // error callback 125 | } = axillo({ 126 | baseURL: 'v2/api/user/' 127 | }); 128 | 129 | function submit() { 130 | mutate({ 131 | name: 'Scrum' 132 | }); 133 | } 134 | 135 | onDone(response) { 136 | console.log(`User ${response.name} created.`); 137 | } 138 | 139 | return { 140 | submit, 141 | loading, 142 | } 143 | } 144 | } 145 | ``` 146 | 147 | ## Options 148 | 149 | #### `baseURL` 150 | 151 | Type: `String` **`required`** 152 | Default: `null` 153 | Description: *URL api used at `query` `mutation`* 154 | 155 | #### `method` 156 | 157 | Type: `String` 158 | Default: `get|post` 159 | Description: *for `query` requests the `get` method is used by default, for `mutate` requests the `post` method is used by default* 160 | 161 | #### `apiClient` 162 | 163 | Type: `Function` 164 | Default: [Axios](https://github.com/axios/axios) 165 | Description: *HTTP client* 166 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { ref, watch } from 'vue'; 2 | import axios from 'axios'; 3 | import { rexios } from 'rexios'; 4 | 5 | const axillo = (config = {}) => { 6 | const baseURL = config.baseURL; 7 | 8 | if (!baseURL) { 9 | throw new Error('must be parameter `baseURL` must be defined'); 10 | } 11 | 12 | const apiClient = config.apiClient || axios; 13 | const params = ref({}); 14 | const result = ref(null); 15 | const loading = ref(false); 16 | let onSuccess = () => {}; 17 | let onFail = () => {}; 18 | 19 | function request(defaultMethod, data) { 20 | const { method, args } = rexios({ 21 | method: defaultMethod, 22 | baseURL, 23 | ...config, 24 | params: data 25 | }); 26 | loading.value = true; 27 | return apiClient[method](...args) 28 | .then(response => { 29 | loading.value = false; 30 | result.value = response; 31 | onSuccess(response); 32 | }) 33 | .catch(error => { 34 | onFail(error) 35 | }); 36 | } 37 | 38 | function query(queryParams = {}) { 39 | return request('get', queryParams); 40 | } 41 | 42 | function mutate(mutateParams = {}) { 43 | return request('post', mutateParams); 44 | } 45 | 46 | watch(params, value => { 47 | query(value); 48 | }); 49 | 50 | function onDone(callback) { 51 | onSuccess = callback; 52 | return onSuccess; 53 | } 54 | 55 | function onError(callback) { 56 | onFail = callback; 57 | return onFail; 58 | } 59 | 60 | return { 61 | query, 62 | mutate, 63 | params, 64 | loading, 65 | result, 66 | onDone, 67 | onError, 68 | }; 69 | } 70 | 71 | 72 | export default axillo; 73 | -------------------------------------------------------------------------------- /test/snapshots/test-core.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/test-core.js` 2 | 3 | The actual snapshot is saved in `test-core.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## Should return simple default parametrs and method 8 | 9 | > Snapshot 1 10 | 11 | { 12 | loading: RefImpl { 13 | __v_isRef: true, 14 | _rawValue: false, 15 | _shallow: false, 16 | _value: false, 17 | }, 18 | mutate: Function mutate {}, 19 | onDone: Function onDone {}, 20 | onError: Function onError {}, 21 | params: RefImpl { 22 | __v_isRef: true, 23 | _rawValue: {}, 24 | _shallow: false, 25 | _value: {}, 26 | }, 27 | query: Function query {}, 28 | result: RefImpl { 29 | __v_isRef: true, 30 | _rawValue: null, 31 | _shallow: false, 32 | _value: null, 33 | }, 34 | } 35 | -------------------------------------------------------------------------------- /test/snapshots/test-core.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Scrum/vue-axillo/6542d43dc274a17fd6da2a845335e97967ca0f00/test/snapshots/test-core.js.snap -------------------------------------------------------------------------------- /test/test-core.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import axillo from '../src'; 3 | 4 | const baseURL = 'test/api/url'; 5 | 6 | test('Should return type function', t => { 7 | t.is(typeof(axillo), 'function'); 8 | }); 9 | 10 | 11 | test('Should throw error baseURL', t => { 12 | const error = t.throws(() => { 13 | axillo(); 14 | }, {instanceOf: Error}); 15 | 16 | t.is(error.message, 'must be parameter `baseURL` must be defined'); 17 | }); 18 | 19 | test('Should return simple default parametrs and method', t => { 20 | t.snapshot(axillo({baseURL})); 21 | }); 22 | 23 | test('Should return result null, loading false', t => { 24 | const { 25 | result, 26 | loading 27 | } = axillo({baseURL}); 28 | 29 | t.is(result.value, null); 30 | t.false(loading.value); 31 | }); 32 | -------------------------------------------------------------------------------- /test/test-mutate.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import axillo from '../src'; 3 | 4 | const baseURL = 'https://jsonplaceholder.typicode.com/users/'; 5 | 6 | test.cb('mutate and default method post', t => { 7 | const { 8 | mutate, 9 | onDone 10 | } = axillo({baseURL}); 11 | 12 | mutate(); 13 | 14 | onDone(response => { 15 | t.is(response.status, 201); 16 | t.end(); 17 | }) 18 | }); 19 | 20 | test.cb('mutate and method delete', t => { 21 | const { 22 | mutate, 23 | onDone 24 | } = axillo({ 25 | baseURL, 26 | method: 'delete' 27 | }); 28 | 29 | mutate({ 30 | id: 1 31 | }); 32 | 33 | onDone(response => { 34 | t.is(response.status, 200); 35 | t.end(); 36 | }) 37 | }); 38 | -------------------------------------------------------------------------------- /test/test-query.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import axillo from '../src'; 3 | 4 | const baseURL = 'https://jsonplaceholder.typicode.com/users/'; 5 | 6 | test('query', async t => { 7 | const { 8 | query, 9 | result 10 | } = axillo({baseURL}); 11 | 12 | await query(); 13 | 14 | t.is(result.value.data.length, 10); 15 | }); 16 | 17 | test('query with params', async t => { 18 | const { 19 | query, 20 | result 21 | } = axillo({baseURL}); 22 | 23 | await query({ 24 | id: 1 25 | }); 26 | 27 | t.is(result.value.data.name, 'Leanne Graham'); 28 | }); -------------------------------------------------------------------------------- /xo.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | fix: true, 3 | space: true, 4 | rules: { 5 | 'unicorn/no-fn-reference-in-iterator': 'off', 6 | 'promise/prefer-await-to-then': 'off' 7 | } 8 | }; 9 | --------------------------------------------------------------------------------