├── demo ├── .env ├── mix-manifest.json ├── rapid │ ├── rapid.js │ ├── Core │ │ ├── Rapid.js │ │ ├── Defaults.js │ │ ├── Routes.js │ │ ├── Url.js │ │ ├── Crud.js │ │ ├── Core.js │ │ └── Request.js │ ├── Debug │ │ ├── Logger.js │ │ └── Debugger.js │ └── auth.js ├── index.html ├── src │ └── app.js ├── package.json ├── webpack.mix.js └── webpack.config.js ├── .npmignore ├── .gitignore ├── .travis.yml ├── src ├── rapid.js ├── common │ └── url.js ├── core │ ├── rapid.js │ ├── defaults.js │ ├── routes.js │ ├── custom-route.js │ ├── url.js │ ├── crud.js │ ├── core.js │ └── request.js ├── debug │ ├── logger.js │ └── debugger.js └── auth.js ├── dist ├── rapid.js ├── common │ └── url.js ├── core │ ├── defaults.js │ ├── rapid.js │ ├── custom-route.js │ ├── routes.js │ ├── url.js │ ├── crud.js │ ├── core.js │ └── request.js ├── debug │ ├── logger.js │ └── debugger.js └── auth.js ├── test ├── helpers.js ├── routes.test.js ├── extension.test.js ├── id.test.js ├── with.test.js ├── crud.test.js ├── base.test.js ├── auth.test.js ├── custom-route.test.js └── request.test.js ├── .eslintrc.js ├── package.json └── README.md /demo/.env: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /demo 2 | demo 3 | -------------------------------------------------------------------------------- /demo/mix-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/dist/app.js": "/dist/app.js" 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | /node_modules 3 | .nyc_output 4 | npm-debug.log 5 | demo/node_modules 6 | /demo 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - node 4 | cache: 5 | directories: 6 | - "node_modules" 7 | branches: 8 | only: 9 | - master -------------------------------------------------------------------------------- /src/rapid.js: -------------------------------------------------------------------------------- 1 | import Rapid from './core/rapid'; 2 | import Auth from './auth'; 3 | 4 | module.exports = Rapid; 5 | module.exports.Rapid = Rapid; 6 | module.exports.Auth = Auth; 7 | -------------------------------------------------------------------------------- /demo/rapid/rapid.js: -------------------------------------------------------------------------------- 1 | import Rapid from './core/rapid'; 2 | import Auth from './auth'; 3 | 4 | module.exports = Rapid; 5 | module.exports.Rapid = Rapid; 6 | module.exports.Auth = Auth; 7 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Rapid tests 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /dist/rapid.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _rapid = require('./core/rapid'); 4 | 5 | var _rapid2 = _interopRequireDefault(_rapid); 6 | 7 | var _auth = require('./auth'); 8 | 9 | var _auth2 = _interopRequireDefault(_auth); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | module.exports = _rapid2.default; 14 | module.exports.Rapid = _rapid2.default; 15 | module.exports.Auth = _auth2.default; -------------------------------------------------------------------------------- /src/common/url.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This just makes sure there are no double slashes and no trailing 3 | * slash unless the config for it is set. 4 | * 5 | * @param {String} url a url to sanitize 6 | * @param {Boolean} keepTrailingSlash a url to sanitize 7 | * @return {String} 8 | */ 9 | export function sanitizeUrl (url = '', keepTrailingSlash = false) { 10 | url = url.replace(/([^:]\/)\/+/g, '$1').replace(/\?$/, '').replace(/^(\/\/)/, '/'); 11 | 12 | if (!keepTrailingSlash) { 13 | url = url.replace(/\/$/, ''); 14 | } 15 | 16 | return url; 17 | } 18 | 19 | export default { 20 | sanitizeUrl, 21 | }; 22 | -------------------------------------------------------------------------------- /src/core/rapid.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Rapid.js v0.0.14 3 | * (c) 2017 Drew J Bartlett (https://drewjbartlett.com) 4 | * Released under the MIT License. 5 | */ 6 | 7 | /** 8 | * The inheritance of the classes 9 | * 10 | * Core ---> Url 11 | * Url ---> Routes 12 | * Routes ---> Request 13 | * Request ---> Relationships 14 | * Relationships ---> Crud 15 | * Crud ---> Rapid 16 | * 17 | */ 18 | 19 | import Crud from './crud'; 20 | 21 | class Rapid extends Crud { 22 | 23 | constructor (config) { 24 | super(config); 25 | } 26 | 27 | } 28 | 29 | export default Rapid; 30 | -------------------------------------------------------------------------------- /demo/src/app.js: -------------------------------------------------------------------------------- 1 | // import Rapid from './../rapid/rapid'; 2 | import { Rapid, Auth } from './../rapid/rapid'; 3 | 4 | window.Rapid = Rapid; 5 | 6 | window.test = new Rapid({ modelName: 'test', debug: true, extension: 'xml' }); 7 | window.auth = new Auth({ modelName: 'user', debug: true }); 8 | 9 | const routes = [ 10 | { 11 | type: 'get', 12 | name: 'simple_test', 13 | url: '/hi/how/are/you', 14 | }, 15 | 16 | { 17 | type: 'post', 18 | name: 'simple_test_two', 19 | url: '/user/{id}/{username}/profile', 20 | }, 21 | ]; 22 | 23 | window.newRapid = new Rapid({ customRoutes: routes }); -------------------------------------------------------------------------------- /demo/rapid/Core/Rapid.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Rapid.js v0.0.14 3 | * (c) 2017 Drew J Bartlett (https://drewjbartlett.com) 4 | * Released under the MIT License. 5 | */ 6 | 7 | /** 8 | * The inheritance of the classes 9 | * 10 | * Core ---> Url 11 | * Url ---> Routes 12 | * Routes ---> Request 13 | * Request ---> Relationships 14 | * Relationships ---> Crud 15 | * Crud ---> Rapid 16 | * 17 | */ 18 | 19 | import Crud from './crud'; 20 | 21 | class Rapid extends Crud { 22 | 23 | constructor (config) { 24 | super(config); 25 | } 26 | 27 | } 28 | 29 | export default Rapid; 30 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "cross-env NODE_ENV=development webpack --progress --hide-modules", 8 | "watch": "cross-env NODE_ENV=development webpack --watch --progress --hide-modules", 9 | "hot": "cross-env NODE_ENV=development webpack-dev-server --inline --hot", 10 | "production": "cross-env NODE_ENV=production webpack --progress --hide-modules" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "babel-cli": "^6.24.0", 17 | "laravel-mix": "^0.10.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/helpers.js: -------------------------------------------------------------------------------- 1 | import Rapid from './../src/rapid'; 2 | import Auth from './../src/auth'; 3 | 4 | /** 5 | * Create an auth model for testing 6 | * @param {Object} config 7 | */ 8 | export function createAuthModel (config) { 9 | const auth = new Auth(Object.assign(config, { debug: true })); 10 | auth.debugger.logEnabled = false; 11 | 12 | return auth; 13 | } 14 | 15 | /** 16 | * Create a model for testing 17 | * @param {Object} config 18 | */ 19 | export function createModel(config) { 20 | const auth = new Rapid(Object.assign(config, { debug: true })); 21 | auth.debugger.logEnabled = false; 22 | 23 | return auth; 24 | } 25 | 26 | export default { 27 | createAuthModel, 28 | createModel, 29 | }; 30 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'parser': 'babel-eslint', 3 | 'extends': 'airbnb-base', 4 | 'rules': { 5 | 'indent': ['error', 4], 6 | 'padded-blocks': 0, 7 | 'class-methods-use-this': ['error', { 'exceptMethods': ['boot'] }], 8 | 'no-useless-constructor': 0, 9 | 'no-param-reassign': 0, 10 | 'no-console': 0, 11 | 'no-return-assign': 0, 12 | 'prefer-rest-params': 0, 13 | 'consistent-return': 0, 14 | 'space-before-function-paren': 0 15 | }, 16 | 'globals': { 17 | 'it': true, 18 | 'describe': true, 19 | 'beforeAll': true, 20 | 'beforeEach': true, 21 | 'afterEach': true, 22 | 'afterAll': true, 23 | 'before': true, 24 | 'after': true, 25 | 'expect': true, 26 | 'jest': true 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/debug/logger.js: -------------------------------------------------------------------------------- 1 | class Logger { 2 | constructor (prefix) { 3 | this.prefix = prefix; 4 | this.firedDebugNotice = false; 5 | this.fireDebugNotice(); 6 | } 7 | 8 | fireDebugNotice () { 9 | if (!this.firedDebugNotice) { 10 | // this.debug('You are running Rapid in debug mode. All requests will be mimicked.'); 11 | 12 | this.firedDebugNotice = true; 13 | } 14 | } 15 | 16 | debug (message) { 17 | console.info(`[${this.prefix}]: ${message}`); 18 | } 19 | 20 | log (message) { 21 | console.log(`[${this.prefix}]:`, message); 22 | } 23 | 24 | warn (message) { 25 | console.warn(`[${this.prefix} warn]:`, message); 26 | } 27 | 28 | } 29 | 30 | export default new Logger('rapid js'); 31 | -------------------------------------------------------------------------------- /demo/rapid/Debug/Logger.js: -------------------------------------------------------------------------------- 1 | class Logger { 2 | constructor (prefix) { 3 | this.prefix = prefix; 4 | this.firedDebugNotice = false; 5 | this.fireDebugNotice(); 6 | } 7 | 8 | fireDebugNotice () { 9 | if (!this.firedDebugNotice) { 10 | // this.debug('You are running Rapid in debug mode. All requests will be mimicked.'); 11 | 12 | this.firedDebugNotice = true; 13 | } 14 | } 15 | 16 | debug (message) { 17 | console.info(`[${this.prefix}]: ${message}`); 18 | } 19 | 20 | log (message) { 21 | console.log(`[${this.prefix}]:`, message); 22 | } 23 | 24 | warn (message) { 25 | console.warn(`[${this.prefix} warn]:`, message); 26 | } 27 | 28 | } 29 | 30 | export default new Logger('rapid js'); 31 | -------------------------------------------------------------------------------- /dist/common/url.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.sanitizeUrl = sanitizeUrl; 7 | /** 8 | * This just makes sure there are no double slashes and no trailing 9 | * slash unless the config for it is set. 10 | * 11 | * @param {String} url a url to sanitize 12 | * @param {Boolean} keepTrailingSlash a url to sanitize 13 | * @return {String} 14 | */ 15 | function sanitizeUrl() { 16 | var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; 17 | var keepTrailingSlash = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; 18 | 19 | url = url.replace(/([^:]\/)\/+/g, '$1').replace(/\?$/, '').replace(/^(\/\/)/, '/'); 20 | 21 | if (!keepTrailingSlash) { 22 | url = url.replace(/\/$/, ''); 23 | } 24 | 25 | return url; 26 | } 27 | 28 | exports.default = { 29 | sanitizeUrl: sanitizeUrl 30 | }; -------------------------------------------------------------------------------- /test/routes.test.js: -------------------------------------------------------------------------------- 1 | import { createModel } from './helpers'; 2 | 3 | describe('The routes are generated properly based off config', () => { 4 | it('that routeDelimiter will work', () => { 5 | const postModel = createModel({ 6 | modelName: 'PacificCrestTrail', 7 | routeDelimeter: '_', 8 | }); 9 | 10 | postModel.find(1); 11 | expect(postModel.debugger.data.lastUrl).toBe('api/pacific_crest_trail/1'); 12 | 13 | postModel.all(); 14 | expect(postModel.debugger.data.lastUrl).toBe('api/pacific_crest_trails'); 15 | }); 16 | 17 | it('that caseSensitive will work', () => { 18 | const postModel = createModel({ 19 | modelName: 'PacificCrestTrail', 20 | caseSensitive: true, 21 | }); 22 | 23 | postModel.find(1); 24 | expect(postModel.debugger.data.lastUrl).toBe('api/PacificCrestTrail/1'); 25 | 26 | postModel.all(); 27 | expect(postModel.debugger.data.lastUrl).toBe('api/PacificCrestTrails'); 28 | }); 29 | }); 30 | 31 | -------------------------------------------------------------------------------- /test/extension.test.js: -------------------------------------------------------------------------------- 1 | import { createModel } from './helpers'; 2 | 3 | const doc = createModel({ 4 | modelName: 'document', 5 | extension: 'xml', 6 | }); 7 | 8 | describe('The extension feature should work', () => { 9 | it('CRUD works with extension', () => { 10 | doc.id(23).find(); 11 | expect(doc.debugger.data.lastUrl).toBe('api/document/23.xml'); 12 | 13 | doc.id(234).save({}); 14 | expect(doc.debugger.data.lastUrl).toBe('api/document/234/update.xml'); 15 | 16 | doc.id(456).destroy(); 17 | expect(doc.debugger.data.lastUrl).toBe('api/document/456/destroy.xml'); 18 | }); 19 | 20 | const issue = createModel({ 21 | modelName: 'issue', 22 | defaultRoute: 'collection', 23 | extension: 'json', 24 | }); 25 | 26 | it('works with extension', () => { 27 | issue.get(); 28 | expect(issue.debugger.data.lastUrl).toBe('api/issues.json'); 29 | 30 | issue.post(); 31 | expect(issue.debugger.data.lastUrl).toBe('api/issues.json'); 32 | 33 | issue.id(234).get(); 34 | expect(issue.debugger.data.lastUrl).toBe('api/issues/234.json'); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/core/defaults.js: -------------------------------------------------------------------------------- 1 | export default { 2 | modelName: '', 3 | 4 | primaryKey: '', 5 | 6 | baseURL: 'api', 7 | 8 | trailingSlash: false, 9 | 10 | extension: '', 11 | 12 | caseSensitive: false, 13 | 14 | routeDelimeter: '-', 15 | 16 | globalParameters: { 17 | 18 | }, 19 | 20 | suffixes: { 21 | create: 'create', 22 | update: 'update', 23 | destroy: 'destroy', 24 | }, 25 | 26 | methods: { 27 | create: 'post', 28 | update: 'post', 29 | destroy: 'post', 30 | }, 31 | 32 | routes: { 33 | model: '', 34 | collection: '', 35 | any: '', 36 | }, 37 | 38 | customRoutes: {}, 39 | 40 | defaultRoute: 'model', 41 | 42 | debug: false, 43 | 44 | apiConfig: { 45 | 46 | }, 47 | 48 | allowedRequestTypes: ['get', 'post', 'put', 'patch', 'head', 'delete'], 49 | 50 | // eslint-disable-next-line no-unused-vars 51 | beforeRequest (type, url) { 52 | 53 | }, 54 | 55 | // eslint-disable-next-line no-unused-vars 56 | afterRequest (response) { 57 | 58 | }, 59 | 60 | // eslint-disable-next-line no-unused-vars 61 | onError (response) { 62 | 63 | }, 64 | }; 65 | -------------------------------------------------------------------------------- /demo/rapid/Core/Defaults.js: -------------------------------------------------------------------------------- 1 | export default { 2 | modelName: '', 3 | 4 | primaryKey: '', 5 | 6 | baseURL: 'api', 7 | 8 | trailingSlash: false, 9 | 10 | extension: '', 11 | 12 | caseSensitive: false, 13 | 14 | routeDelimeter: '-', 15 | 16 | globalParameters: { 17 | 18 | }, 19 | 20 | suffixes: { 21 | create: 'create', 22 | update: 'update', 23 | destroy: 'destroy', 24 | }, 25 | 26 | methods: { 27 | create: 'post', 28 | update: 'post', 29 | destroy: 'post', 30 | }, 31 | 32 | routes: { 33 | model: '', 34 | collection: '', 35 | any: '', 36 | }, 37 | 38 | customRoutes: {}, 39 | 40 | defaultRoute: 'model', 41 | 42 | debug: false, 43 | 44 | apiConfig: { 45 | 46 | }, 47 | 48 | allowedRequestTypes: ['get', 'post', 'put', 'patch', 'head', 'delete'], 49 | 50 | // eslint-disable-next-line no-unused-vars 51 | beforeRequest (type, url) { 52 | 53 | }, 54 | 55 | // eslint-disable-next-line no-unused-vars 56 | afterRequest (response) { 57 | 58 | }, 59 | 60 | // eslint-disable-next-line no-unused-vars 61 | onError (response) { 62 | 63 | }, 64 | }; 65 | -------------------------------------------------------------------------------- /test/id.test.js: -------------------------------------------------------------------------------- 1 | import { createModel } from './helpers'; 2 | 3 | 4 | const shark = createModel({ 5 | modelName: 'shark', 6 | }); 7 | 8 | describe('The id() method works as it should', () => { 9 | it('works with basic CRUD', () => { 10 | shark.id(23).find(); 11 | expect(shark.debugger.data.lastUrl).toBe('api/shark/23'); 12 | 13 | shark.id(234).save({}); 14 | expect(shark.debugger.data.lastUrl).toBe('api/shark/234/update'); 15 | 16 | shark.id(456).destroy(); 17 | expect(shark.debugger.data.lastUrl).toBe('api/shark/456/destroy'); 18 | }); 19 | 20 | it('works with other requests', () => { 21 | shark.id(23).get(); 22 | expect(shark.debugger.data.lastUrl).toBe('api/shark/23'); 23 | 24 | shark.id(789).get('fish', 'are', 'friends', 'not', 'food'); 25 | expect(shark.debugger.data.lastUrl).toBe('api/shark/789/fish/are/friends/not/food'); 26 | 27 | shark.id(23).post('swim'); 28 | expect(shark.debugger.data.lastUrl).toBe('api/shark/23/swim'); 29 | 30 | shark.id(234).delete('eat', 'fish'); 31 | expect(shark.debugger.data.lastUrl).toBe('api/shark/234/eat/fish'); 32 | 33 | shark.id(456).patch(); 34 | expect(shark.debugger.data.lastUrl).toBe('api/shark/456'); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /test/with.test.js: -------------------------------------------------------------------------------- 1 | import { createModel } from './helpers'; 2 | 3 | const postModel = createModel({ 4 | modelName: 'post', 5 | }); 6 | 7 | describe('The with methods all work as should', () => { 8 | it('that withParams works', () => { 9 | postModel.collection.withParams({ limit: 20 }).findBy('category', 'featured'); 10 | 11 | expect(postModel.debugger.data.lastUrl).toBe('api/posts/category/featured?limit=20'); 12 | }); 13 | 14 | it('that withParam works', () => { 15 | postModel.withParam('status', 'published').get(); 16 | 17 | expect(postModel.debugger.data.lastUrl).toBe('api/post?status=published'); 18 | 19 | postModel.collection.withParam('status', 'published').findBy('category', 'featured'); 20 | 21 | expect(postModel.debugger.data.lastUrl).toBe('api/posts/category/featured?status=published'); 22 | }); 23 | 24 | it('that withData works', () => { 25 | postModel.collection.withData({ 26 | params: { 27 | limit: 20, published: true, orderBy: 'commentCount', order: 'desc', 28 | }, 29 | }).findBy('category', 'featured'); 30 | 31 | expect(postModel.debugger.data.lastUrl).toBe('api/posts/category/featured?limit=20&published=true&orderBy=commentCount&order=desc'); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /dist/core/defaults.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = { 7 | modelName: '', 8 | 9 | primaryKey: '', 10 | 11 | baseURL: 'api', 12 | 13 | trailingSlash: false, 14 | 15 | extension: '', 16 | 17 | caseSensitive: false, 18 | 19 | routeDelimeter: '-', 20 | 21 | globalParameters: {}, 22 | 23 | suffixes: { 24 | create: 'create', 25 | update: 'update', 26 | destroy: 'destroy' 27 | }, 28 | 29 | methods: { 30 | create: 'post', 31 | update: 'post', 32 | destroy: 'post' 33 | }, 34 | 35 | routes: { 36 | model: '', 37 | collection: '', 38 | any: '' 39 | }, 40 | 41 | customRoutes: {}, 42 | 43 | defaultRoute: 'model', 44 | 45 | debug: false, 46 | 47 | apiConfig: {}, 48 | 49 | allowedRequestTypes: ['get', 'post', 'put', 'patch', 'head', 'delete'], 50 | 51 | // eslint-disable-next-line no-unused-vars 52 | beforeRequest: function beforeRequest(type, url) {}, 53 | 54 | 55 | // eslint-disable-next-line no-unused-vars 56 | afterRequest: function afterRequest(response) {}, 57 | 58 | 59 | // eslint-disable-next-line no-unused-vars 60 | onError: function onError(response) {} 61 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rapid.js", 3 | "version": "1.0.5", 4 | "description": "", 5 | "main": "dist/rapid.js", 6 | "scripts": { 7 | "test": "npm run unit", 8 | "compile": "babel --presets=es2015 -d dist src", 9 | "copy-dev": "npm run compile && rm -rf ./demo/rapid && cp -R ./dist ./demo/rapid", 10 | "prepublish": "npm run compile", 11 | "lint": "eslint src/**/*.js test/**/*.js", 12 | "unit": "jest --maxWorkers 2", 13 | "unit:watch": "jest test/**/*.test.js --watch" 14 | }, 15 | "babel": { 16 | "presets": [ 17 | "es2015" 18 | ] 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/rapidjs/rapid.js.git" 23 | }, 24 | "keywords": [], 25 | "author": "", 26 | "license": "ISC", 27 | "bugs": { 28 | "url": "https://github.com/rapidjs/rapid.js/issues" 29 | }, 30 | "homepage": "https://github.com/rapidjs/rapid.js#readme", 31 | "devDependencies": { 32 | "babel-cli": "^6.24.0", 33 | "babel-eslint": "^8.0.2", 34 | "babel-preset-es2015": "^6.24.0", 35 | "eslint": "^4.11.0", 36 | "eslint-config-airbnb-base": "^12.1.0", 37 | "eslint-config-airbnb-standard": "^1.6.5", 38 | "eslint-plugin-import": "^2.8.0", 39 | "jest": "^21.2.1" 40 | }, 41 | "dependencies": { 42 | "axios": "^0.16.0", 43 | "lodash": "^4.17.4", 44 | "pluralize": "^4.0.0", 45 | "qs": "^6.4.0" 46 | }, 47 | "publishConfig": { 48 | "access": "public" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/debug/debugger.js: -------------------------------------------------------------------------------- 1 | import qs from 'qs'; 2 | 3 | export default class { 4 | constructor (caller) { 5 | this.caller = caller; 6 | this.data = {}; 7 | this.logEnabled = true; 8 | } 9 | 10 | fakeRequest (type, url) { 11 | const params = this.caller.parseRequestData(type); 12 | const lastUrl = this.setLastUrl(type, url, ...params); 13 | 14 | this.setLastRequest(...arguments); 15 | 16 | if (this.logEnabled) { 17 | this.caller.logger.debug(`${this.caller.config.modelName} made a ${type.toUpperCase()} request (${lastUrl})`); 18 | this.caller.logger.log(params); 19 | } 20 | 21 | this.caller.afterRequest({}); 22 | 23 | return lastUrl; 24 | } 25 | 26 | setLastUrl (type, url, params = {}) { 27 | let lastUrl = ''; 28 | 29 | if (['put', 'post', 'patch'].includes(type)) { 30 | lastUrl = this.caller.sanitizeUrl([this.caller.config.baseURL, url].join('/')); 31 | } else { 32 | const urlParams = params.params; 33 | const stringified = urlParams ? `?${qs.stringify(urlParams)}` : ''; 34 | 35 | lastUrl = this.caller.sanitizeUrl([this.caller.config.baseURL, url].join('/')) + stringified; 36 | } 37 | 38 | lastUrl = this.caller.sanitizeUrl(lastUrl); 39 | 40 | this.data.lastUrl = lastUrl; 41 | 42 | return lastUrl; 43 | } 44 | 45 | setLastRequest (type, url, data = {}, options = {}) { 46 | this.data.lastRequest = { 47 | type, 48 | url, 49 | data, 50 | options, 51 | }; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /demo/rapid/Debug/Debugger.js: -------------------------------------------------------------------------------- 1 | import qs from 'qs'; 2 | 3 | export default class { 4 | constructor (caller) { 5 | this.caller = caller; 6 | this.data = {}; 7 | this.logEnabled = true; 8 | } 9 | 10 | fakeRequest (type, url) { 11 | const params = this.caller.parseRequestData(type); 12 | const lastUrl = this.setLastUrl(type, url, ...params); 13 | 14 | this.setLastRequest(...arguments); 15 | 16 | if (this.logEnabled) { 17 | this.caller.logger.debug(`${this.caller.config.modelName} made a ${type.toUpperCase()} request (${lastUrl})`); 18 | this.caller.logger.log(params); 19 | } 20 | 21 | this.caller.afterRequest({}); 22 | 23 | return lastUrl; 24 | } 25 | 26 | setLastUrl (type, url, params = {}) { 27 | let lastUrl = ''; 28 | 29 | if (['put', 'post', 'patch'].includes(type)) { 30 | lastUrl = this.caller.sanitizeUrl([this.caller.config.baseURL, url].join('/')); 31 | } else { 32 | const urlParams = params.params; 33 | const stringified = urlParams ? `?${qs.stringify(urlParams)}` : ''; 34 | 35 | lastUrl = this.caller.sanitizeUrl([this.caller.config.baseURL, url].join('/')) + stringified; 36 | } 37 | 38 | lastUrl = this.caller.sanitizeUrl(lastUrl); 39 | 40 | this.data.lastUrl = lastUrl; 41 | 42 | return lastUrl; 43 | } 44 | 45 | setLastRequest (type, url, data = {}, options = {}) { 46 | this.data.lastRequest = { 47 | type, 48 | url, 49 | data, 50 | options, 51 | }; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /demo/rapid/auth.js: -------------------------------------------------------------------------------- 1 | import { defaultsDeep } from 'lodash'; 2 | import Rapid from './core/rapid'; 3 | 4 | const authConfig = { 5 | auth: { 6 | routes: { 7 | login: 'login', 8 | logout: 'logout', 9 | auth: 'auth', 10 | register: 'register', 11 | }, 12 | 13 | methods: { 14 | login: 'post', 15 | logout: 'post', 16 | auth: 'get', 17 | register: 'post', 18 | }, 19 | 20 | modelPrefix: false, 21 | }, 22 | }; 23 | 24 | class Auth extends Rapid { 25 | 26 | constructor (config) { 27 | config = defaultsDeep(config, authConfig); 28 | config.modelName = config.modelName ? config.modelName : 'auth'; 29 | 30 | super(config); 31 | } 32 | 33 | login (credentials = {}) { 34 | return this[this.modelPrefix].withParams(credentials) 35 | .withOption('auth', credentials) 36 | .buildRequest(this.config.auth.methods.login, this.config.auth.routes.login); 37 | } 38 | 39 | logout () { 40 | return this[this.modelPrefix] 41 | .buildRequest(this.config.auth.methods.logout, this.config.auth.routes.logout); 42 | } 43 | 44 | check () { 45 | return this[this.modelPrefix] 46 | .buildRequest(this.config.auth.methods.auth, this.config.auth.routes.auth); 47 | } 48 | 49 | register (credentials = {}) { 50 | return this[this.modelPrefix].withParams(credentials) 51 | .buildRequest(this.config.auth.methods.register, this.config.auth.routes.register); 52 | } 53 | 54 | get modelPrefix () { 55 | return this.config.auth.modelPrefix ? 'model' : 'any'; 56 | } 57 | 58 | } 59 | 60 | export default Auth; 61 | -------------------------------------------------------------------------------- /src/auth.js: -------------------------------------------------------------------------------- 1 | import defaultsDeep from 'lodash/defaultsDeep'; 2 | import Rapid from './core/rapid'; 3 | 4 | const authConfig = { 5 | auth: { 6 | routes: { 7 | login: 'login', 8 | logout: 'logout', 9 | auth: 'auth', 10 | register: 'register', 11 | }, 12 | 13 | methods: { 14 | login: 'post', 15 | logout: 'post', 16 | auth: 'get', 17 | register: 'post', 18 | }, 19 | 20 | modelPrefix: false, 21 | }, 22 | }; 23 | 24 | class Auth extends Rapid { 25 | 26 | constructor (config) { 27 | config = defaultsDeep(config, authConfig); 28 | config.modelName = config.modelName ? config.modelName : 'auth'; 29 | 30 | super(config); 31 | } 32 | 33 | login (credentials = {}) { 34 | return this[this.modelPrefix].withParams(credentials) 35 | .withOption('auth', credentials) 36 | .buildRequest(this.config.auth.methods.login, this.config.auth.routes.login); 37 | } 38 | 39 | logout () { 40 | return this[this.modelPrefix] 41 | .buildRequest(this.config.auth.methods.logout, this.config.auth.routes.logout); 42 | } 43 | 44 | check () { 45 | return this[this.modelPrefix] 46 | .buildRequest(this.config.auth.methods.auth, this.config.auth.routes.auth); 47 | } 48 | 49 | register (credentials = {}) { 50 | return this[this.modelPrefix].withParams(credentials) 51 | .buildRequest(this.config.auth.methods.register, this.config.auth.routes.register); 52 | } 53 | 54 | get modelPrefix () { 55 | return this.config.auth.modelPrefix ? 'model' : 'any'; 56 | } 57 | 58 | } 59 | 60 | export default Auth; 61 | -------------------------------------------------------------------------------- /demo/rapid/Core/Routes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The Rapid Routes 3 | */ 4 | 5 | import { kebabCase } from 'lodash'; 6 | import pluralize from 'pluralize'; 7 | import Url from './url'; 8 | 9 | class Routes extends Url { 10 | 11 | constructor (config) { 12 | super(config); 13 | } 14 | 15 | /** 16 | * Set the current route. 17 | * This will set the current route to either model, collection, 18 | * or any to make appropriate requests 19 | * Can also be changed by calling rapid.model.func() or rapid.collection.func() 20 | * 21 | * @param route The route to set 22 | */ 23 | setCurrentRoute (route) { 24 | this.currentRoute = route; 25 | } 26 | 27 | /** 28 | * Set the routes for the URL based off model/collection and config 29 | * 30 | * @param route The key of the route to be set 31 | */ 32 | setRoute (route) { 33 | let newRoute = ''; 34 | const formattedRoute = { 35 | model: this.config.modelName, 36 | collection: pluralize(this.config.modelName), 37 | any: '', 38 | }; 39 | 40 | if (this.config.routes[route] !== '') { 41 | newRoute = this.config.routes[route]; 42 | } else { 43 | newRoute = kebabCase(formattedRoute[route]).replace(/-/g, this.config.routeDelimeter); 44 | 45 | if (this.config.caseSensitive) { 46 | newRoute = formattedRoute[route]; 47 | } 48 | } 49 | 50 | this.routes[route] = newRoute; 51 | } 52 | 53 | /** 54 | * Loop through the routes and set them 55 | */ 56 | setRoutes () { 57 | ['model', 'collection'].forEach(route => this.setRoute(route)); 58 | } 59 | } 60 | 61 | export default Routes; 62 | -------------------------------------------------------------------------------- /src/core/routes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The Rapid Routes 3 | */ 4 | 5 | import kebabCase from 'lodash/kebabCase'; 6 | import pluralize from 'pluralize'; 7 | import Url from './url'; 8 | 9 | class Routes extends Url { 10 | 11 | constructor (config) { 12 | super(config); 13 | } 14 | 15 | /** 16 | * Set the current route. 17 | * This will set the current route to either model, collection, 18 | * or any to make appropriate requests 19 | * Can also be changed by calling rapid.model.func() or rapid.collection.func() 20 | * 21 | * @param route The route to set 22 | */ 23 | setCurrentRoute (route) { 24 | this.currentRoute = route; 25 | } 26 | 27 | /** 28 | * Set the routes for the URL based off model/collection and config 29 | * 30 | * @param route The key of the route to be set 31 | */ 32 | setRoute (route) { 33 | let newRoute = ''; 34 | const formattedRoute = { 35 | model: this.config.modelName, 36 | collection: pluralize(this.config.modelName), 37 | any: '', 38 | }; 39 | 40 | if (this.config.routes[route] !== '') { 41 | newRoute = this.config.routes[route]; 42 | } else { 43 | newRoute = kebabCase(formattedRoute[route]).replace(/-/g, this.config.routeDelimeter); 44 | 45 | if (this.config.caseSensitive) { 46 | newRoute = formattedRoute[route]; 47 | } 48 | } 49 | 50 | this.routes[route] = newRoute; 51 | } 52 | 53 | /** 54 | * Loop through the routes and set them 55 | */ 56 | setRoutes () { 57 | ['model', 'collection'].forEach(route => this.setRoute(route)); 58 | } 59 | } 60 | 61 | export default Routes; 62 | -------------------------------------------------------------------------------- /dist/debug/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 10 | 11 | var Logger = function () { 12 | function Logger(prefix) { 13 | _classCallCheck(this, Logger); 14 | 15 | this.prefix = prefix; 16 | this.firedDebugNotice = false; 17 | this.fireDebugNotice(); 18 | } 19 | 20 | _createClass(Logger, [{ 21 | key: 'fireDebugNotice', 22 | value: function fireDebugNotice() { 23 | if (!this.firedDebugNotice) { 24 | // this.debug('You are running Rapid in debug mode. All requests will be mimicked.'); 25 | 26 | this.firedDebugNotice = true; 27 | } 28 | } 29 | }, { 30 | key: 'debug', 31 | value: function debug(message) { 32 | console.info('[' + this.prefix + ']: ' + message); 33 | } 34 | }, { 35 | key: 'log', 36 | value: function log(message) { 37 | console.log('[' + this.prefix + ']:', message); 38 | } 39 | }, { 40 | key: 'warn', 41 | value: function warn(message) { 42 | console.warn('[' + this.prefix + ' warn]:', message); 43 | } 44 | }]); 45 | 46 | return Logger; 47 | }(); 48 | 49 | exports.default = new Logger('rapid js'); -------------------------------------------------------------------------------- /test/crud.test.js: -------------------------------------------------------------------------------- 1 | import { createModel } from './helpers'; 2 | 3 | const userModel = createModel({ 4 | modelName: 'user', 5 | }); 6 | 7 | describe('The basic CRUD methods should work', () => { 8 | it('that it will have the right url for find', () => { 9 | userModel.find(1); 10 | 11 | expect(userModel.debugger.data.lastUrl).toBe('api/user/1'); 12 | }); 13 | 14 | it('that it will have the right url for all', () => { 15 | userModel.all(); 16 | 17 | expect(userModel.debugger.data.lastUrl).toBe('api/users'); 18 | }); 19 | 20 | const myModel = createModel({ 21 | modelName: 'model', 22 | }); 23 | 24 | it('that it will have the right url for findBy', () => { 25 | myModel.findBy('key', 'value'); 26 | 27 | expect(myModel.debugger.data.lastUrl).toBe('api/model/key/value'); 28 | 29 | myModel.collection.findBy('key', 'value'); 30 | 31 | expect(myModel.debugger.data.lastUrl).toBe('api/models/key/value'); 32 | }); 33 | 34 | const testModel = createModel({ 35 | modelName: 'testModel', 36 | suffixes: { 37 | create: 'new', 38 | update: 'save', 39 | destroy: 'delete', 40 | }, 41 | }); 42 | 43 | it('that create will have the correct url', () => { 44 | testModel.create({}); 45 | expect(testModel.debugger.data.lastUrl).toBe('api/test-model/new'); 46 | }); 47 | 48 | it('that update will work', () => { 49 | testModel.update({}); 50 | expect(testModel.debugger.data.lastUrl).toBe('api/test-model/save'); 51 | 52 | testModel.update(12345, {}); 53 | expect(testModel.debugger.data.lastUrl).toBe('api/test-model/12345/save'); 54 | }); 55 | 56 | it('that destroy will work', () => { 57 | testModel.destroy({}); 58 | expect(testModel.debugger.data.lastUrl).toBe('api/test-model/delete'); 59 | 60 | testModel.destroy(12345, {}); 61 | expect(testModel.debugger.data.lastUrl).toBe('api/test-model/12345/delete'); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /demo/webpack.mix.js: -------------------------------------------------------------------------------- 1 | let mix = require('laravel-mix'); 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Mix Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Mix provides a clean, fluent API for defining some Webpack build steps 9 | | for your Laravel application. By default, we are compiling the Sass 10 | | file for your application, as well as bundling up your JS files. 11 | | 12 | */ 13 | 14 | mix.js('src/app.js', 'dist/'); 15 | 16 | // Full API 17 | // mix.js(src, output); 18 | // mix.react(src, output); <-- Identical to mix.js(), but registers React Babel compilation. 19 | // mix.extract(vendorLibs); 20 | // mix.sass(src, output); 21 | // mix.less(src, output); 22 | // mix.stylus(src, output); 23 | // mix.browserSync('my-site.dev'); 24 | // mix.combine(files, destination); 25 | // mix.babel(files, destination); <-- Identical to mix.combine(), but also includes Babel compilation. 26 | // mix.copy(from, to); 27 | // mix.copyDirectory(fromDir, toDir); 28 | // mix.minify(file); 29 | // mix.sourceMaps(); // Enable sourcemaps 30 | // mix.version(); // Enable versioning. 31 | // mix.disableNotifications(); 32 | // mix.setPublicPath('path/to/public'); 33 | // mix.setResourceRoot('prefix/for/resource/locators'); 34 | // mix.autoload({}); <-- Will be passed to Webpack's ProvidePlugin. 35 | // mix.webpackConfig({}); <-- Override webpack.config.js, without editing the file directly. 36 | // mix.then(function () {}) <-- Will be triggered each time Webpack finishes building. 37 | // mix.options({ 38 | // extractVueStyles: false, // Extract .vue component styling to file, rather than inline. 39 | // processCssUrls: true, // Process/optimize relative stylesheet url()'s. Set to false, if you don't want them touched. 40 | // purifyCss: false, // Remove unused CSS selectors. 41 | // uglify: {}, // Uglify-specific options. https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin 42 | // postCss: [] // Post-CSS options: https://github.com/postcss/postcss/blob/master/docs/plugins.md 43 | // }); 44 | -------------------------------------------------------------------------------- /test/base.test.js: -------------------------------------------------------------------------------- 1 | import Rapid from './../src/rapid'; 2 | 3 | class GalleryWrapper extends Rapid { 4 | boot () { 5 | this.baseURL = 'https://mysite.com/api'; 6 | this.modelName = 'Gallery'; 7 | } 8 | 9 | tagSearch (query) { 10 | return this.append('tagsearch').withParam('query', query); 11 | } 12 | 13 | categorySearch (query) { 14 | return this.append('categorysearch').withParam('query', query); 15 | } 16 | 17 | paginate (pagination) { 18 | return this.withParams(pagination); 19 | } 20 | 21 | taxonomy (taxonomy) { 22 | return this.append(taxonomy); 23 | } 24 | 25 | json () { 26 | return this.append('json'); 27 | } 28 | 29 | xml () { 30 | return this.append('xml'); 31 | } 32 | } 33 | 34 | describe('Extending and creating a wrapper', () => { 35 | const wrapper = new GalleryWrapper({ 36 | globalParameters: { 37 | key: 'YOUR_API_KEY', 38 | }, 39 | debug: true, 40 | }); 41 | wrapper.debugger.logEnabled = false; 42 | 43 | it('should generate proper urls from the wrapper methods', () => { 44 | wrapper.tagSearch('orange').json().get(); 45 | expect(wrapper.debugger.data.lastUrl).toBe('https://mysite.com/api/gallery/tagsearch/json?query=orange&key=YOUR_API_KEY'); 46 | 47 | wrapper.categorySearch('nature').xml().get(); 48 | expect(wrapper.debugger.data.lastUrl).toBe('https://mysite.com/api/gallery/categorysearch/xml?query=nature&key=YOUR_API_KEY'); 49 | 50 | 51 | wrapper.id(45).taxonomy('tags').json().get(); 52 | expect(wrapper.debugger.data.lastUrl).toBe('https://mysite.com/api/gallery/45/tags/json?key=YOUR_API_KEY'); 53 | 54 | 55 | wrapper.id(45).taxonomy('categories').xml().get(); 56 | expect(wrapper.debugger.data.lastUrl).toBe('https://mysite.com/api/gallery/45/categories/xml?key=YOUR_API_KEY'); 57 | 58 | wrapper.id(45).paginate({ page: 1, perPage: 20 }).xml().get(); 59 | expect(wrapper.debugger.data.lastUrl).toBe('https://mysite.com/api/gallery/45/xml?page=1&perPage=20&key=YOUR_API_KEY'); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /src/core/custom-route.js: -------------------------------------------------------------------------------- 1 | class CustomRoute { 2 | constructor (route = {}, config = {}) { 3 | // setup the default route object 4 | this.route = Object.assign({ 5 | url: '', 6 | type: 'get', 7 | name: '', 8 | }, route); 9 | 10 | // setup the default config 11 | this.config = Object.assign({ 12 | routeParams: {}, 13 | }, config); 14 | } 15 | 16 | /** 17 | * This replaces any interpolated params with items passed in via the routeParams object 18 | * 19 | * @return {string} 20 | */ 21 | replaceURLParams () { 22 | let url = this.rawURL; 23 | 24 | // only do this if we have route params && params to replace 25 | if (this.urlParams.length && Object.keys(this.config.routeParams).length !== 0) { 26 | // replace each occurrence of the param with the value passed in 27 | this.urlParams.forEach((param) => { 28 | url = url.replace(`{${param}}`, this.config.routeParams[param]); 29 | }); 30 | } 31 | 32 | return url; 33 | } 34 | 35 | /** 36 | * Check if the url has interpolated {} in them 37 | * 38 | * @return {array} 39 | */ 40 | get urlParams () { 41 | // eslint-disable-next-line 42 | let params = this.rawURL.match(/{\s*[\w\.]+\s*}/g); 43 | 44 | // if we have params, strip off the {} 45 | if (params !== null) { 46 | return params.map(x => 47 | // eslint-disable-next-line 48 | x.match(/[\w\.]+/)[0]); 49 | } 50 | 51 | return []; 52 | } 53 | 54 | /** 55 | * Returns the properly prepared URL 56 | * 57 | * @return {string} 58 | */ 59 | get url () { 60 | return this.replaceURLParams(); 61 | } 62 | 63 | /** 64 | * Returns the raw url from the route which would 65 | * contain any interpolations 66 | * 67 | * @return {string} 68 | */ 69 | get rawURL () { 70 | return this.route.url; 71 | } 72 | 73 | /** 74 | * Returns the route name 75 | * 76 | * @return {string} 77 | */ 78 | get name () { 79 | return this.route.name; 80 | } 81 | 82 | /** 83 | * Returns the request type 84 | * 85 | * @return {string} 86 | */ 87 | get type () { 88 | return this.route.type; 89 | } 90 | } 91 | 92 | export default CustomRoute; 93 | -------------------------------------------------------------------------------- /test/auth.test.js: -------------------------------------------------------------------------------- 1 | import { createAuthModel } from './helpers'; 2 | 3 | const user = createAuthModel({ modelName: 'user' }); 4 | 5 | describe('Rapid Auth Model', () => { 6 | 7 | it('should generate the login url', () => { 8 | user.login(); 9 | expect(user.debugger.data.lastUrl).toBe('api/login'); 10 | }); 11 | 12 | it('should generate the logout url', () => { 13 | user.logout(); 14 | expect(user.debugger.data.lastUrl).toBe('api/logout'); 15 | }); 16 | 17 | it('should generate a route to auth check', () => { 18 | user.check(); 19 | expect(user.debugger.data.lastUrl).toBe('api/auth'); 20 | }); 21 | 22 | it('should generate a route to auth register', () => { 23 | user.register(); 24 | expect(user.debugger.data.lastUrl).toBe('api/register'); 25 | }); 26 | 27 | const userTwo = createAuthModel({ modelName: 'User', auth: { modelPrefix: true } }); 28 | 29 | it('should contain a model prefix when set in config', () => { 30 | userTwo.register(); 31 | expect(userTwo.debugger.data.lastUrl).toBe('api/user/register'); 32 | }); 33 | 34 | const userFour = createAuthModel({ 35 | modelName: 'User', 36 | auth: { 37 | routes: { 38 | login: 'login-user', 39 | logout: ['logout', 'user'], 40 | auth: 'authenticate', 41 | register: 'new', 42 | }, 43 | }, 44 | }); 45 | 46 | it('should allow overriding in the auth routes', () => { 47 | userFour.login(); 48 | expect(userFour.debugger.data.lastUrl).toBe('api/login-user'); 49 | 50 | userFour.logout(); 51 | expect(userFour.debugger.data.lastUrl).toBe('api/logout/user'); 52 | 53 | userFour.check(); 54 | expect(userFour.debugger.data.lastUrl).toBe('api/authenticate'); 55 | 56 | userFour.register(); 57 | expect(userFour.debugger.data.lastUrl).toBe('api/new'); 58 | }); 59 | 60 | const userFive = createAuthModel({ 61 | modelName: 'User', 62 | auth: { 63 | methods: { 64 | login: 'get', 65 | logout: 'delete', 66 | auth: 'get', 67 | register: 'patch', 68 | }, 69 | }, 70 | }); 71 | 72 | it('should allow overriding the method types', () => { 73 | userFive.login(); 74 | expect(userFive.debugger.data.lastRequest.type).toBe('get'); 75 | 76 | userFive.logout(); 77 | expect(userFive.debugger.data.lastRequest.type).toBe('delete'); 78 | 79 | userFive.check(); 80 | expect(userFive.debugger.data.lastRequest.type).toBe('get'); 81 | 82 | userFive.register(); 83 | expect(userFive.debugger.data.lastRequest.type).toBe('patch'); 84 | }); 85 | 86 | }); 87 | -------------------------------------------------------------------------------- /src/core/url.js: -------------------------------------------------------------------------------- 1 | /** 2 | * URL Methods 3 | */ 4 | 5 | import isArray from 'lodash/isArray'; 6 | import Core from './core'; 7 | import { sanitizeUrl } from '../common/url'; 8 | 9 | class Url extends Core { 10 | constructor (config) { 11 | super(config); 12 | } 13 | 14 | /** 15 | * Based off the current route that's set this will take a set of params 16 | * and split it into a URL. This will then reset the route to the default 17 | * route after building the URL. 18 | * 19 | * @param ...params Can be any length of params that will be joined by / 20 | */ 21 | makeUrl (...params) { 22 | 23 | if (this.config.trailingSlash) { 24 | params.push(''); 25 | } 26 | 27 | let url = this.sanitizeUrl([this.routes[this.currentRoute]].concat(params).join('/')); 28 | 29 | // strip the extra . 30 | // make sure routes don't need to regenerate 31 | if (this.config.extension) { 32 | url += `.${this.config.extension}`; 33 | } 34 | 35 | // reset currentRoute 36 | this.setCurrentRoute(this.config.defaultRoute); 37 | 38 | return url; 39 | } 40 | 41 | /** 42 | * This just makes sure there are no double slashes and no trailing 43 | * slash unless the config for it is set. 44 | * 45 | * @param url a url to sanitize 46 | */ 47 | sanitizeUrl (url) { 48 | return sanitizeUrl(url, this.config.trailingSlash); 49 | } 50 | 51 | /** 52 | * Reset an URL params set from a relationship 53 | */ 54 | resetURLParams () { 55 | this.urlParams = false; 56 | } 57 | 58 | /** 59 | * Set the URL params 60 | */ 61 | setURLParams (urlParams = [], prepend = false, overwrite = false) { 62 | this.urlParams = this.urlParams || []; 63 | 64 | if (!isArray(urlParams)) { 65 | urlParams = [urlParams]; 66 | } 67 | 68 | if (overwrite) { 69 | this.urlParams = urlParams; 70 | 71 | return this; 72 | } 73 | 74 | if (prepend) { 75 | this.urlParams = urlParams.concat(this.urlParams); 76 | } else { 77 | this.urlParams = this.urlParams.concat(urlParams); 78 | } 79 | 80 | return this; 81 | } 82 | 83 | // consider making a .url() alias of the above method? 84 | 85 | url (...params) { 86 | this.setURLParams(...params); 87 | 88 | return this; 89 | } 90 | 91 | prepend (params) { 92 | this.setURLParams(params, true); 93 | 94 | return this; 95 | } 96 | 97 | append (params) { 98 | this.setURLParams(params); 99 | 100 | return this; 101 | } 102 | 103 | } 104 | 105 | export default Url; 106 | -------------------------------------------------------------------------------- /demo/rapid/Core/Url.js: -------------------------------------------------------------------------------- 1 | /** 2 | * URL Methods 3 | */ 4 | 5 | import { isArray } from 'lodash'; 6 | import Core from './core'; 7 | import { sanitizeUrl } from '../common/url'; 8 | 9 | class Url extends Core { 10 | constructor (config) { 11 | super(config); 12 | } 13 | 14 | /** 15 | * Based off the current route that's set this will take a set of params 16 | * and split it into a URL. This will then reset the route to the default 17 | * route after building the URL. 18 | * 19 | * @param ...params Can be any length of params that will be joined by / 20 | */ 21 | makeUrl (...params) { 22 | 23 | if (this.config.trailingSlash) { 24 | params.push(''); 25 | } 26 | 27 | let url = this.sanitizeUrl([this.routes[this.currentRoute]].concat(params).join('/')); 28 | 29 | // strip the extra . 30 | // make sure routes don't need to regenerate 31 | if (this.config.extension) { 32 | url += `.${this.config.extension}`; 33 | } 34 | 35 | // reset currentRoute 36 | this.setCurrentRoute(this.config.defaultRoute); 37 | 38 | return url; 39 | } 40 | 41 | /** 42 | * This just makes sure there are no double slashes and no trailing 43 | * slash unless the config for it is set. 44 | * 45 | * @param url a url to sanitize 46 | */ 47 | sanitizeUrl (url) { 48 | return sanitizeUrl(url, this.config.trailingSlash); 49 | } 50 | 51 | /** 52 | * Reset an URL params set from a relationship 53 | */ 54 | resetURLParams () { 55 | this.urlParams = false; 56 | } 57 | 58 | /** 59 | * Set the URL params 60 | */ 61 | setURLParams (urlParams = [], prepend = false, overwrite = false) { 62 | this.urlParams = this.urlParams || []; 63 | 64 | if (!isArray(urlParams)) { 65 | urlParams = [urlParams]; 66 | } 67 | 68 | if (overwrite) { 69 | this.urlParams = urlParams; 70 | 71 | return this; 72 | } 73 | 74 | if (prepend) { 75 | this.urlParams = urlParams.concat(this.urlParams); 76 | } else { 77 | this.urlParams = this.urlParams.concat(urlParams); 78 | } 79 | 80 | return this; 81 | } 82 | 83 | // consider making a .url() alias of the above method? 84 | 85 | url (...params) { 86 | this.setURLParams(...params); 87 | 88 | return this; 89 | } 90 | 91 | prepend (params) { 92 | this.setURLParams(params, true); 93 | 94 | return this; 95 | } 96 | 97 | append (params) { 98 | this.setURLParams(params); 99 | 100 | return this; 101 | } 102 | 103 | } 104 | 105 | export default Url; 106 | -------------------------------------------------------------------------------- /dist/debug/debugger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _qs = require('qs'); 10 | 11 | var _qs2 = _interopRequireDefault(_qs); 12 | 13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 14 | 15 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } 16 | 17 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 18 | 19 | var _class = function () { 20 | function _class(caller) { 21 | _classCallCheck(this, _class); 22 | 23 | this.caller = caller; 24 | this.data = {}; 25 | this.logEnabled = true; 26 | } 27 | 28 | _createClass(_class, [{ 29 | key: 'fakeRequest', 30 | value: function fakeRequest(type, url) { 31 | var params = this.caller.parseRequestData(type); 32 | var lastUrl = this.setLastUrl.apply(this, [type, url].concat(_toConsumableArray(params))); 33 | 34 | this.setLastRequest.apply(this, arguments); 35 | 36 | if (this.logEnabled) { 37 | this.caller.logger.debug(this.caller.config.modelName + ' made a ' + type.toUpperCase() + ' request (' + lastUrl + ')'); 38 | this.caller.logger.log(params); 39 | } 40 | 41 | this.caller.afterRequest({}); 42 | 43 | return lastUrl; 44 | } 45 | }, { 46 | key: 'setLastUrl', 47 | value: function setLastUrl(type, url) { 48 | var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; 49 | 50 | var lastUrl = ''; 51 | 52 | if (['put', 'post', 'patch'].includes(type)) { 53 | lastUrl = this.caller.sanitizeUrl([this.caller.config.baseURL, url].join('/')); 54 | } else { 55 | var urlParams = params.params; 56 | var stringified = urlParams ? '?' + _qs2.default.stringify(urlParams) : ''; 57 | 58 | lastUrl = this.caller.sanitizeUrl([this.caller.config.baseURL, url].join('/')) + stringified; 59 | } 60 | 61 | lastUrl = this.caller.sanitizeUrl(lastUrl); 62 | 63 | this.data.lastUrl = lastUrl; 64 | 65 | return lastUrl; 66 | } 67 | }, { 68 | key: 'setLastRequest', 69 | value: function setLastRequest(type, url) { 70 | var data = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; 71 | var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; 72 | 73 | this.data.lastRequest = { 74 | type: type, 75 | url: url, 76 | data: data, 77 | options: options 78 | }; 79 | } 80 | }]); 81 | 82 | return _class; 83 | }(); 84 | 85 | exports.default = _class; -------------------------------------------------------------------------------- /src/core/crud.js: -------------------------------------------------------------------------------- 1 | /** 2 | * All the CRUD 3 | */ 4 | 5 | import Request from './request'; 6 | 7 | class Crud extends Request { 8 | /** 9 | * Model Only Functions 10 | */ 11 | 12 | /** 13 | * Make a GET request to a url that would retrieve a single model. 14 | * Prepends primaryKey if set 15 | * 16 | * @param id The model's id 17 | */ 18 | find (id) { 19 | return this.model.id(id).get(); 20 | } 21 | 22 | /** 23 | * Make a request to update or destroy a model 24 | * 25 | * @param method The method (update or destroy) 26 | * @param ...params Can be either (id, data) OR (data) 27 | */ 28 | updateOrDestroy (method, ...params) { 29 | const urlParams = []; 30 | const id = params[0]; 31 | let data = params[1]; 32 | 33 | if (Number.isInteger(id)) { 34 | this.id(id); 35 | } else { 36 | [data] = params; 37 | } 38 | 39 | if (Object.prototype.hasOwnProperty.call(this.config.suffixes, method)) { 40 | urlParams.push(this.config.suffixes[method]); 41 | } 42 | 43 | if (method === 'update') { 44 | this.withParams(data); 45 | } 46 | 47 | return this.model.buildRequest(this.config.methods[method], urlParams); 48 | } 49 | 50 | /** 51 | * See updateOrDestroy 52 | */ 53 | update (...params) { 54 | return this.updateOrDestroy('update', ...params); 55 | } 56 | 57 | /** 58 | * Alias of update 59 | * See updateOrDestroy 60 | */ 61 | save (...params) { 62 | return this.update(...params); 63 | } 64 | 65 | /** 66 | * See updateOrDestroy 67 | */ 68 | destroy (...params) { 69 | return this.updateOrDestroy('destroy', ...params); 70 | } 71 | 72 | /** 73 | * Makes a request to create a new model based off the method and suffix for create 74 | * 75 | * @param data The data to be sent over for creation of model 76 | */ 77 | create (data) { 78 | return this.withParams(data) 79 | .buildRequest(this.config.methods.create, this.config.suffixes.create); 80 | } 81 | 82 | /** 83 | * This sets an id for a request 84 | * currently it doens't work with any of the CRUD methods. 85 | * It should work with this. 86 | * 87 | * @param id The id of the model 88 | */ 89 | id (id) { 90 | let params = []; 91 | 92 | // this is checking if primaryKey is true, not if it exists 93 | if (this.config.primaryKey) { 94 | params = [this.config.primaryKey, id]; 95 | } else { 96 | params = [id]; 97 | } 98 | 99 | // needs to prepend 100 | this.prepend(params); 101 | 102 | return this; 103 | } 104 | 105 | /** 106 | * Collection Only Functions 107 | */ 108 | 109 | /** 110 | * Makes a GET request on a collection route 111 | */ 112 | all () { 113 | return this.collection.get(); 114 | } 115 | 116 | /** 117 | * Collection and Model functions 118 | */ 119 | 120 | /** 121 | * Makes a GET request to find a model/collection by key, value 122 | * 123 | * @param key The key to search by 124 | * @param value The value to search by 125 | */ 126 | findBy (key, value) { 127 | const urlParams = [key]; 128 | 129 | if (value) { 130 | urlParams.push(value); 131 | } 132 | 133 | return this.get(...urlParams); 134 | } 135 | } 136 | 137 | export default Crud; 138 | -------------------------------------------------------------------------------- /demo/rapid/Core/Crud.js: -------------------------------------------------------------------------------- 1 | /** 2 | * All the CRUD 3 | */ 4 | 5 | import Request from './request'; 6 | 7 | class Crud extends Request { 8 | /** 9 | * Model Only Functions 10 | */ 11 | 12 | /** 13 | * Make a GET request to a url that would retrieve a single model. 14 | * Prepends primaryKey if set 15 | * 16 | * @param id The model's id 17 | */ 18 | find (id) { 19 | return this.model.id(id).get(); 20 | } 21 | 22 | /** 23 | * Make a request to update or destroy a model 24 | * 25 | * @param method The method (update or destroy) 26 | * @param ...params Can be either (id, data) OR (data) 27 | */ 28 | updateOrDestroy (method, ...params) { 29 | const urlParams = []; 30 | const id = params[0]; 31 | let data = params[1]; 32 | 33 | if (Number.isInteger(id)) { 34 | this.id(id); 35 | } else { 36 | [data] = params; 37 | } 38 | 39 | if (Object.prototype.hasOwnProperty.call(this.config.suffixes, method)) { 40 | urlParams.push(this.config.suffixes[method]); 41 | } 42 | 43 | if (method === 'update') { 44 | this.withParams(data); 45 | } 46 | 47 | return this.model.buildRequest(this.config.methods[method], urlParams); 48 | } 49 | 50 | /** 51 | * See updateOrDestroy 52 | */ 53 | update (...params) { 54 | return this.updateOrDestroy('update', ...params); 55 | } 56 | 57 | /** 58 | * Alias of update 59 | * See updateOrDestroy 60 | */ 61 | save (...params) { 62 | return this.update(...params); 63 | } 64 | 65 | /** 66 | * See updateOrDestroy 67 | */ 68 | destroy (...params) { 69 | return this.updateOrDestroy('destroy', ...params); 70 | } 71 | 72 | /** 73 | * Makes a request to create a new model based off the method and suffix for create 74 | * 75 | * @param data The data to be sent over for creation of model 76 | */ 77 | create (data) { 78 | return this.withParams(data) 79 | .buildRequest(this.config.methods.create, this.config.suffixes.create); 80 | } 81 | 82 | /** 83 | * This sets an id for a request 84 | * currently it doens't work with any of the CRUD methods. 85 | * It should work with this. 86 | * 87 | * @param id The id of the model 88 | */ 89 | id (id) { 90 | let params = []; 91 | 92 | // this is checking if primaryKey is true, not if it exists 93 | if (this.config.primaryKey) { 94 | params = [this.config.primaryKey, id]; 95 | } else { 96 | params = [id]; 97 | } 98 | 99 | // needs to prepend 100 | this.prepend(params); 101 | 102 | return this; 103 | } 104 | 105 | /** 106 | * Collection Only Functions 107 | */ 108 | 109 | /** 110 | * Makes a GET request on a collection route 111 | */ 112 | all () { 113 | return this.collection.get(); 114 | } 115 | 116 | /** 117 | * Collection and Model functions 118 | */ 119 | 120 | /** 121 | * Makes a GET request to find a model/collection by key, value 122 | * 123 | * @param key The key to search by 124 | * @param value The value to search by 125 | */ 126 | findBy (key, value) { 127 | const urlParams = [key]; 128 | 129 | if (value) { 130 | urlParams.push(value); 131 | } 132 | 133 | return this.get(...urlParams); 134 | } 135 | } 136 | 137 | export default Crud; 138 | -------------------------------------------------------------------------------- /test/custom-route.test.js: -------------------------------------------------------------------------------- 1 | import { createModel } from './helpers'; 2 | 3 | const routes = [ 4 | { 5 | name: 'get_user_forget_name', 6 | type: 'get', 7 | url: '/user/forget/name', 8 | }, 9 | 10 | { 11 | name: 'user_save_friends', 12 | type: 'post', 13 | url: '/user/{id}/save/friends', 14 | }, 15 | 16 | { 17 | name: 'multiple_values', 18 | type: 'post', 19 | url: '/user/{id}/{username}', 20 | }, 21 | 22 | { 23 | name: 'multiple_same_values', 24 | type: 'delete', 25 | url: '/user/{id}/{username}/save/{id}', 26 | }, 27 | ]; 28 | 29 | 30 | describe('Custom Routes should work as designed', () => { 31 | it('should create an empty object if no routes are defined', () => { 32 | const model = createModel({ name: 'Drew' }); 33 | 34 | expect(model.customRoutes).toEqual({}); 35 | }); 36 | 37 | it('should load the custom routes into the config', () => { 38 | const model = createModel({ customRoutes: routes }); 39 | 40 | expect(Object.prototype.hasOwnProperty.call(model.customRoutes, 'get_user_forget_name')).toBeTruthy(); 41 | expect(Object.prototype.hasOwnProperty.call(model.customRoutes, 'user_save_friends')).toBeTruthy(); 42 | }); 43 | 44 | const model = createModel({ customRoutes: routes }); 45 | 46 | it('should find a route when route() is called', () => { 47 | expect(model.getCustomRoute('get_user_forget_name').url).toBe('/user/forget/name'); 48 | }); 49 | 50 | it('should find urlParams if they exist', () => { 51 | 52 | expect(model.getCustomRoute('get_user_forget_name').urlParams).toEqual([]); 53 | expect(model.getCustomRoute('user_save_friends').urlParams).toEqual(['id']); 54 | expect(model.getCustomRoute('multiple_values').urlParams).toEqual(['id', 'username']); 55 | expect(model.getCustomRoute('multiple_same_values').urlParams).toEqual(['id', 'username', 'id']); 56 | }); 57 | 58 | it('should replace interpolated variables', () => { 59 | expect(model.generate('user_save_friends3')).toBe(''); 60 | expect(model.generate('user_save_friends', { id: 1 })).toBe('/api/user/1/save/friends'); 61 | expect(model.generate('multiple_same_values', { id: 1, username: 'drew' })).toBe('/api/user/1/drew/save/1'); 62 | }); 63 | 64 | it('should fire the proper request type and url', () => { 65 | model.route('get_user_forget_name'); 66 | 67 | expect(model.debugger.data.lastUrl).toBe('api/user/forget/name'); 68 | expect(model.debugger.data.lastRequest.type).toBe('get'); 69 | 70 | model.route('user_save_friends', { id: 123 }); 71 | expect(model.debugger.data.lastUrl).toBe('api/user/123/save/friends'); 72 | expect(model.debugger.data.lastRequest.type).toBe('post'); 73 | 74 | model.route('multiple_values', { id: 563, username: 'drewjbartlett' }); 75 | expect(model.debugger.data.lastUrl).toBe('api/user/563/drewjbartlett'); 76 | expect(model.debugger.data.lastRequest.type).toBe('post'); 77 | 78 | model.route('multiple_same_values', { id: 563, username: 'drewjbartlett' }); 79 | expect(model.debugger.data.lastUrl).toBe('api/user/563/drewjbartlett/save/563'); 80 | expect(model.debugger.data.lastRequest.type).toBe('delete'); 81 | }); 82 | 83 | const newModel = createModel({ baseURL: '/water', customRoutes: routes }); 84 | 85 | it('should append the baseURL in the custom route', () => { 86 | expect(newModel.generate('get_user_forget_name')).toBe('/water/user/forget/name'); 87 | }); 88 | 89 | const anotherModel = createModel({ baseURL: '', customRoutes: routes }); 90 | 91 | it('should append the baseURL in the custom route', () => { 92 | expect(anotherModel.generate('get_user_forget_name')).toBe('/user/forget/name'); 93 | }); 94 | }); 95 | -------------------------------------------------------------------------------- /dist/core/rapid.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _crud = require('./crud'); 8 | 9 | var _crud2 = _interopRequireDefault(_crud); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 14 | 15 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 16 | 17 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*! 18 | * Rapid.js v0.0.14 19 | * (c) 2017 Drew J Bartlett (https://drewjbartlett.com) 20 | * Released under the MIT License. 21 | */ 22 | 23 | /** 24 | * The inheritance of the classes 25 | * 26 | * Core ---> Url 27 | * Url ---> Routes 28 | * Routes ---> Request 29 | * Request ---> Relationships 30 | * Relationships ---> Crud 31 | * Crud ---> Rapid 32 | * 33 | */ 34 | 35 | var Rapid = function (_Crud) { 36 | _inherits(Rapid, _Crud); 37 | 38 | function Rapid(config) { 39 | _classCallCheck(this, Rapid); 40 | 41 | return _possibleConstructorReturn(this, (Rapid.__proto__ || Object.getPrototypeOf(Rapid)).call(this, config)); 42 | } 43 | 44 | return Rapid; 45 | }(_crud2.default); 46 | 47 | exports.default = Rapid; -------------------------------------------------------------------------------- /dist/auth.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _defaultsDeep = require('lodash/defaultsDeep'); 10 | 11 | var _defaultsDeep2 = _interopRequireDefault(_defaultsDeep); 12 | 13 | var _rapid = require('./core/rapid'); 14 | 15 | var _rapid2 = _interopRequireDefault(_rapid); 16 | 17 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 18 | 19 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 20 | 21 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 22 | 23 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 24 | 25 | var authConfig = { 26 | auth: { 27 | routes: { 28 | login: 'login', 29 | logout: 'logout', 30 | auth: 'auth', 31 | register: 'register' 32 | }, 33 | 34 | methods: { 35 | login: 'post', 36 | logout: 'post', 37 | auth: 'get', 38 | register: 'post' 39 | }, 40 | 41 | modelPrefix: false 42 | } 43 | }; 44 | 45 | var Auth = function (_Rapid) { 46 | _inherits(Auth, _Rapid); 47 | 48 | function Auth(config) { 49 | _classCallCheck(this, Auth); 50 | 51 | config = (0, _defaultsDeep2.default)(config, authConfig); 52 | config.modelName = config.modelName ? config.modelName : 'auth'; 53 | 54 | return _possibleConstructorReturn(this, (Auth.__proto__ || Object.getPrototypeOf(Auth)).call(this, config)); 55 | } 56 | 57 | _createClass(Auth, [{ 58 | key: 'login', 59 | value: function login() { 60 | var credentials = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 61 | 62 | return this[this.modelPrefix].withParams(credentials).withOption('auth', credentials).buildRequest(this.config.auth.methods.login, this.config.auth.routes.login); 63 | } 64 | }, { 65 | key: 'logout', 66 | value: function logout() { 67 | return this[this.modelPrefix].buildRequest(this.config.auth.methods.logout, this.config.auth.routes.logout); 68 | } 69 | }, { 70 | key: 'check', 71 | value: function check() { 72 | return this[this.modelPrefix].buildRequest(this.config.auth.methods.auth, this.config.auth.routes.auth); 73 | } 74 | }, { 75 | key: 'register', 76 | value: function register() { 77 | var credentials = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 78 | 79 | return this[this.modelPrefix].withParams(credentials).buildRequest(this.config.auth.methods.register, this.config.auth.routes.register); 80 | } 81 | }, { 82 | key: 'modelPrefix', 83 | get: function get() { 84 | return this.config.auth.modelPrefix ? 'model' : 'any'; 85 | } 86 | }]); 87 | 88 | return Auth; 89 | }(_rapid2.default); 90 | 91 | exports.default = Auth; -------------------------------------------------------------------------------- /demo/rapid/Core/Core.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The Caramel Core functionality of Rapid 3 | */ 4 | 5 | import axios from 'axios'; 6 | import { defaultsDeep } from 'lodash'; 7 | 8 | import Defaults from './defaults'; 9 | import Debugger from './../debug/debugger'; 10 | import Logger from './../debug/logger'; 11 | 12 | class Core { 13 | constructor (config) { 14 | config = config || {}; 15 | 16 | config = defaultsDeep(config, Defaults); 17 | 18 | this.initialize(config); 19 | } 20 | 21 | /** 22 | * Set any config overrides in this method when extending 23 | */ 24 | boot () { 25 | 26 | } 27 | 28 | /** 29 | * Setup the all of properties. 30 | */ 31 | initialize (config) { 32 | this.config = config; 33 | 34 | this.initializeRoutes(); 35 | 36 | this.boot(); 37 | 38 | this.resetURLParams(); 39 | 40 | this.fireSetters(); 41 | 42 | this.initializeAPI(); 43 | 44 | this.setCurrentRoute(this.config.defaultRoute); 45 | 46 | this.initializeDebugger(); 47 | 48 | this.initializeLogger(); 49 | 50 | this.resetRequestData(); 51 | 52 | this.defineCustomRoutes(); 53 | } 54 | 55 | /** 56 | * Fire the setters. This will make sure the routes are generated properly. 57 | * Consider if this is really even necessary 58 | */ 59 | fireSetters () { 60 | ['baseURL', 'modelName', 'routeDelimeter', 'caseSensitive'].forEach(setter => this[setter] = this.config[setter]); 61 | } 62 | 63 | /** 64 | * Initialze the debugger if debug is set to true. 65 | */ 66 | initializeDebugger () { 67 | this.debugger = this.config.debug ? new Debugger(this) : false; 68 | } 69 | 70 | /** 71 | * Initialze the debugger if debug is set to true. 72 | */ 73 | initializeLogger () { 74 | this.logger = this.config.debug ? Logger : false; 75 | } 76 | 77 | /** 78 | * Initialize the API. 79 | */ 80 | initializeAPI () { 81 | this.api = axios.create(defaultsDeep({ baseURL: this.config.baseURL.replace(/\/$/, '') }, this.config.apiConfig)); 82 | } 83 | 84 | /** 85 | * Initialize the routes. 86 | */ 87 | initializeRoutes () { 88 | this.routes = { 89 | model: '', 90 | collection: '', 91 | any: '', 92 | }; 93 | } 94 | 95 | /** 96 | * Set up the custom routes if we have any 97 | */ 98 | defineCustomRoutes () { 99 | this.customRoutes = {}; 100 | 101 | // if we have custom routes, set up a name:route mapping 102 | if (this.config.customRoutes.length) { 103 | this.config.customRoutes.forEach((route) => { 104 | this.customRoutes[route.name] = route; 105 | }); 106 | } 107 | } 108 | 109 | /** 110 | * Resets the request data 111 | */ 112 | resetRequestData () { 113 | this.requestData = { 114 | params: {}, 115 | options: {}, 116 | }; 117 | } 118 | 119 | /** 120 | * Setters and Getters 121 | */ 122 | 123 | set debug (val) { 124 | if (this.config.debug) { 125 | this.logger.warn('debug mode must explicitly be turned on via the constructor in config.debug'); 126 | } 127 | } 128 | 129 | get collection () { 130 | this.setCurrentRoute('collection'); 131 | 132 | return this; 133 | } 134 | 135 | get model () { 136 | this.setCurrentRoute('model'); 137 | 138 | return this; 139 | } 140 | 141 | get any () { 142 | this.setCurrentRoute('any'); 143 | 144 | return this; 145 | } 146 | 147 | set baseURL (url) { 148 | this.config.baseURL = this.sanitizeUrl(url); 149 | this.initializeAPI(); 150 | } 151 | 152 | set modelName (val) { 153 | this.config.modelName = val; 154 | this.setRoutes(); 155 | } 156 | 157 | set routeDelimeter (val) { 158 | this.config.routeDelimeter = val; 159 | this.setRoutes(); 160 | } 161 | 162 | set caseSensitive (val) { 163 | this.config.caseSensitive = val; 164 | this.setRoutes(); 165 | } 166 | } 167 | 168 | export default Core; 169 | -------------------------------------------------------------------------------- /src/core/core.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The Caramel Core functionality of Rapid 3 | */ 4 | 5 | import axios from 'axios'; 6 | import defaultsDeep from 'lodash/defaultsDeep'; 7 | 8 | import Defaults from './defaults'; 9 | import Debugger from './../debug/debugger'; 10 | import Logger from './../debug/logger'; 11 | 12 | class Core { 13 | constructor (config) { 14 | config = config || {}; 15 | 16 | config = defaultsDeep(config, Defaults); 17 | 18 | this.initialize(config); 19 | } 20 | 21 | /** 22 | * Set any config overrides in this method when extending 23 | */ 24 | boot () { 25 | 26 | } 27 | 28 | /** 29 | * Setup the all of properties. 30 | */ 31 | initialize (config) { 32 | this.config = config; 33 | 34 | this.initializeRoutes(); 35 | 36 | this.boot(); 37 | 38 | this.resetURLParams(); 39 | 40 | this.fireSetters(); 41 | 42 | this.initializeAPI(); 43 | 44 | this.setCurrentRoute(this.config.defaultRoute); 45 | 46 | this.initializeDebugger(); 47 | 48 | this.initializeLogger(); 49 | 50 | this.resetRequestData(); 51 | 52 | this.defineCustomRoutes(); 53 | } 54 | 55 | /** 56 | * Fire the setters. This will make sure the routes are generated properly. 57 | * Consider if this is really even necessary 58 | */ 59 | fireSetters () { 60 | ['baseURL', 'modelName', 'routeDelimeter', 'caseSensitive'].forEach(setter => this[setter] = this.config[setter]); 61 | } 62 | 63 | /** 64 | * Initialze the debugger if debug is set to true. 65 | */ 66 | initializeDebugger () { 67 | this.debugger = this.config.debug ? new Debugger(this) : false; 68 | } 69 | 70 | /** 71 | * Initialze the debugger if debug is set to true. 72 | */ 73 | initializeLogger () { 74 | this.logger = this.config.debug ? Logger : false; 75 | } 76 | 77 | /** 78 | * Initialize the API. 79 | */ 80 | initializeAPI () { 81 | this.api = axios.create(defaultsDeep({ baseURL: this.config.baseURL.replace(/\/$/, '') }, this.config.apiConfig)); 82 | } 83 | 84 | /** 85 | * Initialize the routes. 86 | */ 87 | initializeRoutes () { 88 | this.routes = { 89 | model: '', 90 | collection: '', 91 | any: '', 92 | }; 93 | } 94 | 95 | /** 96 | * Set up the custom routes if we have any 97 | */ 98 | defineCustomRoutes () { 99 | this.customRoutes = {}; 100 | 101 | // if we have custom routes, set up a name:route mapping 102 | if (this.config.customRoutes.length) { 103 | this.config.customRoutes.forEach((route) => { 104 | this.customRoutes[route.name] = route; 105 | }); 106 | } 107 | } 108 | 109 | /** 110 | * Resets the request data 111 | */ 112 | resetRequestData () { 113 | this.requestData = { 114 | params: {}, 115 | options: {}, 116 | }; 117 | } 118 | 119 | /** 120 | * Setters and Getters 121 | */ 122 | 123 | set debug (val) { 124 | if (this.config.debug) { 125 | this.logger.warn('debug mode must explicitly be turned on via the constructor in config.debug'); 126 | } 127 | } 128 | 129 | get collection () { 130 | this.setCurrentRoute('collection'); 131 | 132 | return this; 133 | } 134 | 135 | get model () { 136 | this.setCurrentRoute('model'); 137 | 138 | return this; 139 | } 140 | 141 | get any () { 142 | this.setCurrentRoute('any'); 143 | 144 | return this; 145 | } 146 | 147 | set baseURL (url) { 148 | this.config.baseURL = this.sanitizeUrl(url); 149 | this.initializeAPI(); 150 | } 151 | 152 | set modelName (val) { 153 | this.config.modelName = val; 154 | this.setRoutes(); 155 | } 156 | 157 | set routeDelimeter (val) { 158 | this.config.routeDelimeter = val; 159 | this.setRoutes(); 160 | } 161 | 162 | set caseSensitive (val) { 163 | this.config.caseSensitive = val; 164 | this.setRoutes(); 165 | } 166 | } 167 | 168 | export default Core; 169 | -------------------------------------------------------------------------------- /dist/core/custom-route.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 10 | 11 | var CustomRoute = function () { 12 | function CustomRoute() { 13 | var route = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 14 | var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 15 | 16 | _classCallCheck(this, CustomRoute); 17 | 18 | // setup the default route object 19 | this.route = Object.assign({ 20 | url: '', 21 | type: 'get', 22 | name: '' 23 | }, route); 24 | 25 | // setup the default config 26 | this.config = Object.assign({ 27 | routeParams: {} 28 | }, config); 29 | } 30 | 31 | /** 32 | * This replaces any interpolated params with items passed in via the routeParams object 33 | * 34 | * @return {string} 35 | */ 36 | 37 | 38 | _createClass(CustomRoute, [{ 39 | key: 'replaceURLParams', 40 | value: function replaceURLParams() { 41 | var _this = this; 42 | 43 | var url = this.rawURL; 44 | 45 | // only do this if we have route params && params to replace 46 | if (this.urlParams.length && Object.keys(this.config.routeParams).length !== 0) { 47 | // replace each occurrence of the param with the value passed in 48 | this.urlParams.forEach(function (param) { 49 | url = url.replace('{' + param + '}', _this.config.routeParams[param]); 50 | }); 51 | } 52 | 53 | return url; 54 | } 55 | 56 | /** 57 | * Check if the url has interpolated {} in them 58 | * 59 | * @return {array} 60 | */ 61 | 62 | }, { 63 | key: 'urlParams', 64 | get: function get() { 65 | // eslint-disable-next-line 66 | var params = this.rawURL.match(/{\s*[\w\.]+\s*}/g); 67 | 68 | // if we have params, strip off the {} 69 | if (params !== null) { 70 | return params.map(function (x) { 71 | return ( 72 | // eslint-disable-next-line 73 | x.match(/[\w\.]+/)[0] 74 | ); 75 | }); 76 | } 77 | 78 | return []; 79 | } 80 | 81 | /** 82 | * Returns the properly prepared URL 83 | * 84 | * @return {string} 85 | */ 86 | 87 | }, { 88 | key: 'url', 89 | get: function get() { 90 | return this.replaceURLParams(); 91 | } 92 | 93 | /** 94 | * Returns the raw url from the route which would 95 | * contain any interpolations 96 | * 97 | * @return {string} 98 | */ 99 | 100 | }, { 101 | key: 'rawURL', 102 | get: function get() { 103 | return this.route.url; 104 | } 105 | 106 | /** 107 | * Returns the route name 108 | * 109 | * @return {string} 110 | */ 111 | 112 | }, { 113 | key: 'name', 114 | get: function get() { 115 | return this.route.name; 116 | } 117 | 118 | /** 119 | * Returns the request type 120 | * 121 | * @return {string} 122 | */ 123 | 124 | }, { 125 | key: 'type', 126 | get: function get() { 127 | return this.route.type; 128 | } 129 | }]); 130 | 131 | return CustomRoute; 132 | }(); 133 | 134 | exports.default = CustomRoute; -------------------------------------------------------------------------------- /test/request.test.js: -------------------------------------------------------------------------------- 1 | import { createModel } from './helpers'; 2 | 3 | const lobster = createModel({ modelName: 'Lobster', baseURL: 'http://maine.com/ocean/' }); 4 | 5 | describe('The request functionality should work as expected', () => { 6 | 7 | it('get() works', () => { 8 | 9 | lobster.get('butter'); 10 | 11 | expect((lobster.debugger.data.lastRequest.type === 'get')).toBeTruthy(); 12 | 13 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobster/butter'); 14 | 15 | lobster.collection.get('butter', 'salt'); 16 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobsters/butter/salt'); 17 | 18 | lobster.get('butter', 'salt', 'crackers'); 19 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobster/butter/salt/crackers'); 20 | 21 | }); 22 | 23 | it('post() works', () => { 24 | 25 | lobster.post('butter'); 26 | 27 | expect((lobster.debugger.data.lastRequest.type === 'post')).toBeTruthy(); 28 | 29 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobster/butter'); 30 | 31 | lobster.collection.post('butter', 'salt'); 32 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobsters/butter/salt'); 33 | 34 | lobster.post('butter', 'salt', 'crackers'); 35 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobster/butter/salt/crackers'); 36 | 37 | }); 38 | 39 | it('head() works', () => { 40 | 41 | lobster.head('butter'); 42 | 43 | expect((lobster.debugger.data.lastRequest.type === 'head')).toBeTruthy(); 44 | 45 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobster/butter'); 46 | 47 | lobster.collection.head('butter', 'salt'); 48 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobsters/butter/salt'); 49 | 50 | lobster.head('butter', 'salt', 'crackers'); 51 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobster/butter/salt/crackers'); 52 | 53 | }); 54 | 55 | it('put() works', () => { 56 | 57 | lobster.put('butter'); 58 | 59 | expect((lobster.debugger.data.lastRequest.type === 'put')).toBeTruthy(); 60 | 61 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobster/butter'); 62 | 63 | lobster.collection.put('butter', 'salt'); 64 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobsters/butter/salt'); 65 | 66 | lobster.put('butter', 'salt', 'crackers'); 67 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobster/butter/salt/crackers'); 68 | 69 | }); 70 | 71 | it('patch() works', () => { 72 | 73 | lobster.patch('butter'); 74 | 75 | expect((lobster.debugger.data.lastRequest.type === 'patch')).toBeTruthy(); 76 | 77 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobster/butter'); 78 | 79 | lobster.collection.patch('butter', 'salt'); 80 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobsters/butter/salt'); 81 | 82 | lobster.patch('butter', 'salt', 'crackers'); 83 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobster/butter/salt/crackers'); 84 | 85 | }); 86 | 87 | it('delete() works', () => { 88 | 89 | lobster.delete('butter'); 90 | 91 | expect((lobster.debugger.data.lastRequest.type === 'delete')).toBeTruthy(); 92 | 93 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobster/butter'); 94 | 95 | lobster.collection.delete('butter', 'salt'); 96 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobsters/butter/salt'); 97 | 98 | lobster.delete('butter', 'salt', 'crackers'); 99 | expect(lobster.debugger.data.lastUrl).toBe('http://maine.com/ocean/lobster/butter/salt/crackers'); 100 | 101 | }); 102 | 103 | it('afterRequest gets fired', () => { 104 | const callback = jest.fn(); 105 | const Crab = createModel({ 106 | modelName: 'Crab', 107 | baseURL: 'http://maryland.com/bay/', 108 | afterRequest() { 109 | callback(); 110 | }, 111 | }); 112 | 113 | Crab.find(1); 114 | 115 | expect(callback.mock.calls.length).toBe(1); 116 | }); 117 | 118 | it('beforeRequest gets fired', () => { 119 | const callback = jest.fn(); 120 | const Crab = createModel({ 121 | modelName: 'Crab', 122 | baseURL: 'http://maryland.com/bay/', 123 | beforeRequest() { 124 | callback(); 125 | }, 126 | }); 127 | 128 | Crab.find(1); 129 | 130 | expect(callback.mock.calls.length).toBe(1); 131 | }); 132 | }); 133 | -------------------------------------------------------------------------------- /dist/core/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _kebabCase = require('lodash/kebabCase'); 10 | 11 | var _kebabCase2 = _interopRequireDefault(_kebabCase); 12 | 13 | var _pluralize = require('pluralize'); 14 | 15 | var _pluralize2 = _interopRequireDefault(_pluralize); 16 | 17 | var _url = require('./url'); 18 | 19 | var _url2 = _interopRequireDefault(_url); 20 | 21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 22 | 23 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 24 | 25 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 26 | 27 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** 28 | * The Rapid Routes 29 | */ 30 | 31 | var Routes = function (_Url) { 32 | _inherits(Routes, _Url); 33 | 34 | function Routes(config) { 35 | _classCallCheck(this, Routes); 36 | 37 | return _possibleConstructorReturn(this, (Routes.__proto__ || Object.getPrototypeOf(Routes)).call(this, config)); 38 | } 39 | 40 | /** 41 | * Set the current route. 42 | * This will set the current route to either model, collection, 43 | * or any to make appropriate requests 44 | * Can also be changed by calling rapid.model.func() or rapid.collection.func() 45 | * 46 | * @param route The route to set 47 | */ 48 | 49 | 50 | _createClass(Routes, [{ 51 | key: 'setCurrentRoute', 52 | value: function setCurrentRoute(route) { 53 | this.currentRoute = route; 54 | } 55 | 56 | /** 57 | * Set the routes for the URL based off model/collection and config 58 | * 59 | * @param route The key of the route to be set 60 | */ 61 | 62 | }, { 63 | key: 'setRoute', 64 | value: function setRoute(route) { 65 | var newRoute = ''; 66 | var formattedRoute = { 67 | model: this.config.modelName, 68 | collection: (0, _pluralize2.default)(this.config.modelName), 69 | any: '' 70 | }; 71 | 72 | if (this.config.routes[route] !== '') { 73 | newRoute = this.config.routes[route]; 74 | } else { 75 | newRoute = (0, _kebabCase2.default)(formattedRoute[route]).replace(/-/g, this.config.routeDelimeter); 76 | 77 | if (this.config.caseSensitive) { 78 | newRoute = formattedRoute[route]; 79 | } 80 | } 81 | 82 | this.routes[route] = newRoute; 83 | } 84 | 85 | /** 86 | * Loop through the routes and set them 87 | */ 88 | 89 | }, { 90 | key: 'setRoutes', 91 | value: function setRoutes() { 92 | var _this2 = this; 93 | 94 | ['model', 'collection'].forEach(function (route) { 95 | return _this2.setRoute(route); 96 | }); 97 | } 98 | }]); 99 | 100 | return Routes; 101 | }(_url2.default); 102 | 103 | exports.default = Routes; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | [![npm](https://img.shields.io/npm/v/rapid.js.svg?style=flat-square)](https://www.npmjs.com/package/rapid.js) 6 | [![npm](https://img.shields.io/npm/dt/rapid.js.svg?style=flat-square)](https://www.npmjs.com/package/rapid.js) 7 | [![npm](https://img.shields.io/travis/rapidjs/rapid.js.svg?branch=master&style=flat-square)](https://www.npmjs.com/package/rapid.js) 8 | 9 | ##### An ORM-like Interface and a Router For Your API Requests 10 | ###### Create simple, resusable, and cleaner wrappers, define custom routes, and more for your API requests. 11 | 12 | Read the official docs at [https://rapidjs.io](https://rapidjs.io). 13 | 14 | ## Overview 15 | - [Define Simple Models](#define-simple-models) 16 | - [Easily Customize Your API Requests](#easily-customize-your-api-requests) 17 | - [Create Reusable Base Models](#create-reusable-base-models) 18 | - [Write API Wrappers For Your Endpoints](#write-api-wrappers-for-your-endpoints) 19 | - [Define Custom Routes (New!)](#define-custom-routes) 20 | 21 | ### Define Simple Models 22 | ```js 23 | var post = new Rapid({ modelName: 'Post' }); 24 | 25 | post.find(1).then((response) => { 26 | // GET => /api/post/1 27 | }); 28 | 29 | post.collection.findBy('category', 'featured').then((response) => { 30 | // GET => /api/posts/category/featured 31 | }); 32 | 33 | post.withParams({ limit: 20, order: 'desc' }).all().then((response) => { 34 | // GET => /api/posts?limit=20&order=desc 35 | }); 36 | 37 | post.update(25, { title: 'Rapid JS Is Awesome!' }) 38 | // POST => /api/posts/25/update 39 | 40 | post.destroy(9) 41 | // POST => /api/posts/9/destroy 42 | ``` 43 | Read more about [Rapid Basics](https://rapidjs.io/docs#usage). 44 | 45 | ### Easily Customize Your API Requests 46 | ```js 47 | var post = new Rapid({ 48 | modelName: 'Post', 49 | suffixes: { 50 | destroy: '', 51 | update: 'save' 52 | }, 53 | methods: { 54 | destroy: 'delete' 55 | }, 56 | trailingSlash: true 57 | }); 58 | 59 | post.update(25, { title: 'Rapid JS Is Awesome!' }) 60 | // POST => /api/posts/25/save/ 61 | 62 | post.destroy(9) 63 | // DELETE => /api/posts/9/ 64 | ``` 65 | Read more about [Customizing Your Requests](https://rapidjs.io/docs#config-builder). 66 | 67 | ### Create Reusable Base Models 68 | ```js 69 | class Base extends Rapid { 70 | boot () { 71 | this.baseURL = 'https://myapp.com/api'; 72 | this.config.globalParameters = { key: 'MY_API_KEY' } 73 | } 74 | } 75 | 76 | var photo = new Base({ modelName: 'Photo' }); 77 | var gallery = new Base({ modelName: 'Gallery' }); 78 | var tag = new Base({ modelName: 'Tag' }); 79 | 80 | photo.find(1) 81 | // GET => https://myapp.com/api/photo/1?key=MY_API_KEY 82 | 83 | tag.collection.findBy('color', 'red') 84 | // GET => https://myapp.com/api/tags/color/red?key=MY_API_KEY 85 | 86 | gallery.id(23).get('tags', 'nature') 87 | // GET => https://myapp.com/api/gallery/23/tag/nature?key=MY_API_KEY 88 | ``` 89 | Read more about [Base Models](https://rapidjs.io/docs#extending-base-models). 90 | 91 | ### Write API Wrappers For Your Endpoints 92 | ```js 93 | class GalleryWrapper extends Rapid { 94 | boot () { 95 | this.baseURL = 'https://myapp.com/gallery/api'; 96 | this.modelName = 'Gallery'; 97 | } 98 | 99 | tagSearch (query) { 100 | return this.url('tagsearch').withParam('query', query); 101 | } 102 | 103 | json () { 104 | return this.url('json'); 105 | } 106 | } 107 | 108 | var gallery = new GalleryWrapper({ 109 | globalParameters: { key: 'MY_API_KEY' } 110 | }); 111 | 112 | gallery.tagSearch('nature').json().get().then(...); 113 | // GET https://myapp.com/gallery/api/tagsearch/json?query=nature&key=MY_API_KEY 114 | // GET https://myapp.com/gallery/api/tagsearch/json?query=nature&key=MY_API_KEY 115 | ``` 116 | Read more about [Making a Wrapper](https://rapidjs.io/docs#extending-making-a-wrapper). 117 | 118 | ### Define Custom Routes 119 | 120 | ```js 121 | const customRoutes = [ 122 | { 123 | name: 'web_get_user_preferences', 124 | type: 'get', 125 | url: '/user/preferences', 126 | }, 127 | 128 | { 129 | name: 'web_save_user_preferences', 130 | type: 'post', 131 | url: '/user/{id}/save/preferences' 132 | } 133 | ]; 134 | 135 | const router = new Rapid({ customRoutes, baseURL: '/api' }); 136 | 137 | router.route('web_get_user_preferences').then((response) => {}); 138 | // GET => /api/user/preferences 139 | 140 | router.route('web_save_user_preferences', { id: 12 }, /* { request data } */).then((response) => {}); 141 | // POST => /api/user/12/save/preferences 142 | ``` 143 | 144 | #### Using Your Own HTTP Service 145 | ```js 146 | import http from 'some-http-service'; 147 | 148 | const customRoutes = [ 149 | { 150 | name: 'web_login', 151 | url: '/login' 152 | }, 153 | 154 | { 155 | name: 'api_save_user_preferences',, 156 | url: '/user/{id}/save/preferences' 157 | } 158 | ]; 159 | 160 | const rapid = new Rapid({ customRoutes, baseURL: '' }); 161 | 162 | rapid.generate('web_login') 163 | // returns '/login' 164 | 165 | // use your own service 166 | http.post(rapid.generate('api_save_user_preferences'), { id: 1 }).then()... 167 | ``` 168 | Read more about [Custom Routes](https://rapidjs.io/docs#custom-routes). 169 | 170 | Read the official docs at [https://rapidjs.io](https://rapidjs.io). 171 | -------------------------------------------------------------------------------- /dist/core/url.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _isArray = require('lodash/isArray'); 10 | 11 | var _isArray2 = _interopRequireDefault(_isArray); 12 | 13 | var _core = require('./core'); 14 | 15 | var _core2 = _interopRequireDefault(_core); 16 | 17 | var _url = require('../common/url'); 18 | 19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 20 | 21 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 22 | 23 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 24 | 25 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** 26 | * URL Methods 27 | */ 28 | 29 | var Url = function (_Core) { 30 | _inherits(Url, _Core); 31 | 32 | function Url(config) { 33 | _classCallCheck(this, Url); 34 | 35 | return _possibleConstructorReturn(this, (Url.__proto__ || Object.getPrototypeOf(Url)).call(this, config)); 36 | } 37 | 38 | /** 39 | * Based off the current route that's set this will take a set of params 40 | * and split it into a URL. This will then reset the route to the default 41 | * route after building the URL. 42 | * 43 | * @param ...params Can be any length of params that will be joined by / 44 | */ 45 | 46 | 47 | _createClass(Url, [{ 48 | key: 'makeUrl', 49 | value: function makeUrl() { 50 | for (var _len = arguments.length, params = Array(_len), _key = 0; _key < _len; _key++) { 51 | params[_key] = arguments[_key]; 52 | } 53 | 54 | if (this.config.trailingSlash) { 55 | params.push(''); 56 | } 57 | 58 | var url = this.sanitizeUrl([this.routes[this.currentRoute]].concat(params).join('/')); 59 | 60 | // strip the extra . 61 | // make sure routes don't need to regenerate 62 | if (this.config.extension) { 63 | url += '.' + this.config.extension; 64 | } 65 | 66 | // reset currentRoute 67 | this.setCurrentRoute(this.config.defaultRoute); 68 | 69 | return url; 70 | } 71 | 72 | /** 73 | * This just makes sure there are no double slashes and no trailing 74 | * slash unless the config for it is set. 75 | * 76 | * @param url a url to sanitize 77 | */ 78 | 79 | }, { 80 | key: 'sanitizeUrl', 81 | value: function sanitizeUrl(url) { 82 | return (0, _url.sanitizeUrl)(url, this.config.trailingSlash); 83 | } 84 | 85 | /** 86 | * Reset an URL params set from a relationship 87 | */ 88 | 89 | }, { 90 | key: 'resetURLParams', 91 | value: function resetURLParams() { 92 | this.urlParams = false; 93 | } 94 | 95 | /** 96 | * Set the URL params 97 | */ 98 | 99 | }, { 100 | key: 'setURLParams', 101 | value: function setURLParams() { 102 | var urlParams = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; 103 | var prepend = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; 104 | var overwrite = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; 105 | 106 | this.urlParams = this.urlParams || []; 107 | 108 | if (!(0, _isArray2.default)(urlParams)) { 109 | urlParams = [urlParams]; 110 | } 111 | 112 | if (overwrite) { 113 | this.urlParams = urlParams; 114 | 115 | return this; 116 | } 117 | 118 | if (prepend) { 119 | this.urlParams = urlParams.concat(this.urlParams); 120 | } else { 121 | this.urlParams = this.urlParams.concat(urlParams); 122 | } 123 | 124 | return this; 125 | } 126 | 127 | // consider making a .url() alias of the above method? 128 | 129 | }, { 130 | key: 'url', 131 | value: function url() { 132 | this.setURLParams.apply(this, arguments); 133 | 134 | return this; 135 | } 136 | }, { 137 | key: 'prepend', 138 | value: function prepend(params) { 139 | this.setURLParams(params, true); 140 | 141 | return this; 142 | } 143 | }, { 144 | key: 'append', 145 | value: function append(params) { 146 | this.setURLParams(params); 147 | 148 | return this; 149 | } 150 | }]); 151 | 152 | return Url; 153 | }(_core2.default); 154 | 155 | exports.default = Url; -------------------------------------------------------------------------------- /dist/core/crud.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _request = require('./request'); 10 | 11 | var _request2 = _interopRequireDefault(_request); 12 | 13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 14 | 15 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 16 | 17 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 18 | 19 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** 20 | * All the CRUD 21 | */ 22 | 23 | var Crud = function (_Request) { 24 | _inherits(Crud, _Request); 25 | 26 | function Crud() { 27 | _classCallCheck(this, Crud); 28 | 29 | return _possibleConstructorReturn(this, (Crud.__proto__ || Object.getPrototypeOf(Crud)).apply(this, arguments)); 30 | } 31 | 32 | _createClass(Crud, [{ 33 | key: 'find', 34 | 35 | /** 36 | * Model Only Functions 37 | */ 38 | 39 | /** 40 | * Make a GET request to a url that would retrieve a single model. 41 | * Prepends primaryKey if set 42 | * 43 | * @param id The model's id 44 | */ 45 | value: function find(id) { 46 | return this.model.id(id).get(); 47 | } 48 | 49 | /** 50 | * Make a request to update or destroy a model 51 | * 52 | * @param method The method (update or destroy) 53 | * @param ...params Can be either (id, data) OR (data) 54 | */ 55 | 56 | }, { 57 | key: 'updateOrDestroy', 58 | value: function updateOrDestroy(method) { 59 | var urlParams = []; 60 | 61 | for (var _len = arguments.length, params = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 62 | params[_key - 1] = arguments[_key]; 63 | } 64 | 65 | var id = params[0]; 66 | var data = params[1]; 67 | 68 | if (Number.isInteger(id)) { 69 | this.id(id); 70 | } else { 71 | data = params[0]; 72 | } 73 | 74 | if (Object.prototype.hasOwnProperty.call(this.config.suffixes, method)) { 75 | urlParams.push(this.config.suffixes[method]); 76 | } 77 | 78 | if (method === 'update') { 79 | this.withParams(data); 80 | } 81 | 82 | return this.model.buildRequest(this.config.methods[method], urlParams); 83 | } 84 | 85 | /** 86 | * See updateOrDestroy 87 | */ 88 | 89 | }, { 90 | key: 'update', 91 | value: function update() { 92 | for (var _len2 = arguments.length, params = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 93 | params[_key2] = arguments[_key2]; 94 | } 95 | 96 | return this.updateOrDestroy.apply(this, ['update'].concat(params)); 97 | } 98 | 99 | /** 100 | * Alias of update 101 | * See updateOrDestroy 102 | */ 103 | 104 | }, { 105 | key: 'save', 106 | value: function save() { 107 | return this.update.apply(this, arguments); 108 | } 109 | 110 | /** 111 | * See updateOrDestroy 112 | */ 113 | 114 | }, { 115 | key: 'destroy', 116 | value: function destroy() { 117 | for (var _len3 = arguments.length, params = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { 118 | params[_key3] = arguments[_key3]; 119 | } 120 | 121 | return this.updateOrDestroy.apply(this, ['destroy'].concat(params)); 122 | } 123 | 124 | /** 125 | * Makes a request to create a new model based off the method and suffix for create 126 | * 127 | * @param data The data to be sent over for creation of model 128 | */ 129 | 130 | }, { 131 | key: 'create', 132 | value: function create(data) { 133 | return this.withParams(data).buildRequest(this.config.methods.create, this.config.suffixes.create); 134 | } 135 | 136 | /** 137 | * This sets an id for a request 138 | * currently it doens't work with any of the CRUD methods. 139 | * It should work with this. 140 | * 141 | * @param id The id of the model 142 | */ 143 | 144 | }, { 145 | key: 'id', 146 | value: function id(_id) { 147 | var params = []; 148 | 149 | // this is checking if primaryKey is true, not if it exists 150 | if (this.config.primaryKey) { 151 | params = [this.config.primaryKey, _id]; 152 | } else { 153 | params = [_id]; 154 | } 155 | 156 | // needs to prepend 157 | this.prepend(params); 158 | 159 | return this; 160 | } 161 | 162 | /** 163 | * Collection Only Functions 164 | */ 165 | 166 | /** 167 | * Makes a GET request on a collection route 168 | */ 169 | 170 | }, { 171 | key: 'all', 172 | value: function all() { 173 | return this.collection.get(); 174 | } 175 | 176 | /** 177 | * Collection and Model functions 178 | */ 179 | 180 | /** 181 | * Makes a GET request to find a model/collection by key, value 182 | * 183 | * @param key The key to search by 184 | * @param value The value to search by 185 | */ 186 | 187 | }, { 188 | key: 'findBy', 189 | value: function findBy(key, value) { 190 | var urlParams = [key]; 191 | 192 | if (value) { 193 | urlParams.push(value); 194 | } 195 | 196 | return this.get.apply(this, urlParams); 197 | } 198 | }]); 199 | 200 | return Crud; 201 | }(_request2.default); 202 | 203 | exports.default = Crud; -------------------------------------------------------------------------------- /dist/core/core.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /** 8 | * The Caramel Core functionality of Rapid 9 | */ 10 | 11 | var _axios = require('axios'); 12 | 13 | var _axios2 = _interopRequireDefault(_axios); 14 | 15 | var _defaultsDeep = require('lodash/defaultsDeep'); 16 | 17 | var _defaultsDeep2 = _interopRequireDefault(_defaultsDeep); 18 | 19 | var _defaults = require('./defaults'); 20 | 21 | var _defaults2 = _interopRequireDefault(_defaults); 22 | 23 | var _debugger = require('./../debug/debugger'); 24 | 25 | var _debugger2 = _interopRequireDefault(_debugger); 26 | 27 | var _logger = require('./../debug/logger'); 28 | 29 | var _logger2 = _interopRequireDefault(_logger); 30 | 31 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 32 | 33 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 34 | 35 | var Core = function () { 36 | function Core(config) { 37 | _classCallCheck(this, Core); 38 | 39 | config = config || {}; 40 | 41 | config = (0, _defaultsDeep2.default)(config, _defaults2.default); 42 | 43 | this.initialize(config); 44 | } 45 | 46 | /** 47 | * Set any config overrides in this method when extending 48 | */ 49 | 50 | 51 | _createClass(Core, [{ 52 | key: 'boot', 53 | value: function boot() {} 54 | 55 | /** 56 | * Setup the all of properties. 57 | */ 58 | 59 | }, { 60 | key: 'initialize', 61 | value: function initialize(config) { 62 | this.config = config; 63 | 64 | this.initializeRoutes(); 65 | 66 | this.boot(); 67 | 68 | this.resetURLParams(); 69 | 70 | this.fireSetters(); 71 | 72 | this.initializeAPI(); 73 | 74 | this.setCurrentRoute(this.config.defaultRoute); 75 | 76 | this.initializeDebugger(); 77 | 78 | this.initializeLogger(); 79 | 80 | this.resetRequestData(); 81 | 82 | this.defineCustomRoutes(); 83 | } 84 | 85 | /** 86 | * Fire the setters. This will make sure the routes are generated properly. 87 | * Consider if this is really even necessary 88 | */ 89 | 90 | }, { 91 | key: 'fireSetters', 92 | value: function fireSetters() { 93 | var _this = this; 94 | 95 | ['baseURL', 'modelName', 'routeDelimeter', 'caseSensitive'].forEach(function (setter) { 96 | return _this[setter] = _this.config[setter]; 97 | }); 98 | } 99 | 100 | /** 101 | * Initialze the debugger if debug is set to true. 102 | */ 103 | 104 | }, { 105 | key: 'initializeDebugger', 106 | value: function initializeDebugger() { 107 | this.debugger = this.config.debug ? new _debugger2.default(this) : false; 108 | } 109 | 110 | /** 111 | * Initialze the debugger if debug is set to true. 112 | */ 113 | 114 | }, { 115 | key: 'initializeLogger', 116 | value: function initializeLogger() { 117 | this.logger = this.config.debug ? _logger2.default : false; 118 | } 119 | 120 | /** 121 | * Initialize the API. 122 | */ 123 | 124 | }, { 125 | key: 'initializeAPI', 126 | value: function initializeAPI() { 127 | this.api = _axios2.default.create((0, _defaultsDeep2.default)({ baseURL: this.config.baseURL.replace(/\/$/, '') }, this.config.apiConfig)); 128 | } 129 | 130 | /** 131 | * Initialize the routes. 132 | */ 133 | 134 | }, { 135 | key: 'initializeRoutes', 136 | value: function initializeRoutes() { 137 | this.routes = { 138 | model: '', 139 | collection: '', 140 | any: '' 141 | }; 142 | } 143 | 144 | /** 145 | * Set up the custom routes if we have any 146 | */ 147 | 148 | }, { 149 | key: 'defineCustomRoutes', 150 | value: function defineCustomRoutes() { 151 | var _this2 = this; 152 | 153 | this.customRoutes = {}; 154 | 155 | // if we have custom routes, set up a name:route mapping 156 | if (this.config.customRoutes.length) { 157 | this.config.customRoutes.forEach(function (route) { 158 | _this2.customRoutes[route.name] = route; 159 | }); 160 | } 161 | } 162 | 163 | /** 164 | * Resets the request data 165 | */ 166 | 167 | }, { 168 | key: 'resetRequestData', 169 | value: function resetRequestData() { 170 | this.requestData = { 171 | params: {}, 172 | options: {} 173 | }; 174 | } 175 | 176 | /** 177 | * Setters and Getters 178 | */ 179 | 180 | }, { 181 | key: 'debug', 182 | set: function set(val) { 183 | if (this.config.debug) { 184 | this.logger.warn('debug mode must explicitly be turned on via the constructor in config.debug'); 185 | } 186 | } 187 | }, { 188 | key: 'collection', 189 | get: function get() { 190 | this.setCurrentRoute('collection'); 191 | 192 | return this; 193 | } 194 | }, { 195 | key: 'model', 196 | get: function get() { 197 | this.setCurrentRoute('model'); 198 | 199 | return this; 200 | } 201 | }, { 202 | key: 'any', 203 | get: function get() { 204 | this.setCurrentRoute('any'); 205 | 206 | return this; 207 | } 208 | }, { 209 | key: 'baseURL', 210 | set: function set(url) { 211 | this.config.baseURL = this.sanitizeUrl(url); 212 | this.initializeAPI(); 213 | } 214 | }, { 215 | key: 'modelName', 216 | set: function set(val) { 217 | this.config.modelName = val; 218 | this.setRoutes(); 219 | } 220 | }, { 221 | key: 'routeDelimeter', 222 | set: function set(val) { 223 | this.config.routeDelimeter = val; 224 | this.setRoutes(); 225 | } 226 | }, { 227 | key: 'caseSensitive', 228 | set: function set(val) { 229 | this.config.caseSensitive = val; 230 | this.setRoutes(); 231 | } 232 | }]); 233 | 234 | return Core; 235 | }(); 236 | 237 | exports.default = Core; -------------------------------------------------------------------------------- /demo/rapid/Core/Request.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The Re-Quest to find the API 3 | */ 4 | 5 | import { isArray, defaultsDeep, set } from 'lodash'; 6 | import Routes from './routes'; 7 | import CustomRoute from './custom-route'; 8 | 9 | class Request extends Routes { 10 | constructor (config) { 11 | super(config); 12 | } 13 | 14 | /** 15 | * Parse the request data prior to passing it to axios 16 | * 17 | * @param type The request type 18 | */ 19 | parseRequestData (type) { 20 | const requestData = []; 21 | const { options } = this.requestData; 22 | let { params } = this.requestData; 23 | 24 | // axios handles the options differently for the request type 25 | if (['put', 'post', 'patch'].includes(type)) { 26 | params = defaultsDeep(params, this.config.globalParameters); 27 | requestData.push(params); 28 | requestData.push(options); 29 | } else { 30 | options.params = defaultsDeep(params, this.config.globalParameters); 31 | requestData.push(options); 32 | } 33 | 34 | return requestData; 35 | } 36 | 37 | /** 38 | * Make the request 39 | * 40 | * @param type The Request type 41 | * @param url The url 42 | */ 43 | request (type, url) { 44 | type = type.toLowerCase(); 45 | 46 | if (!this.isAllowedRequestType(type)) { 47 | return; 48 | } 49 | 50 | this.beforeRequest(type, url); 51 | 52 | if (this.config.debug) { 53 | return this.debugger.fakeRequest(type, url); 54 | } 55 | 56 | return new Promise((resolve, reject) => { 57 | this.api[type].call(this, this.sanitizeUrl(url), ...this.parseRequestData(type)) 58 | .then((response) => { 59 | this.afterRequest(response); 60 | 61 | resolve(response); 62 | }) 63 | .catch((error) => { 64 | this.onError(error); 65 | 66 | reject(error); 67 | }); 68 | }); 69 | } 70 | 71 | /** 72 | * Checks if is a valid request type 73 | * 74 | * @param type The request type 75 | */ 76 | isAllowedRequestType (type) { 77 | if (!this.config.allowedRequestTypes.includes(type)) { 78 | if (this.config.debug) { 79 | this.logger.warn(`'${type}' is not included in allowedRequestTypes: [${this.config.allowedRequestTypes.join(', ')}]`); 80 | } 81 | 82 | return false; 83 | } 84 | 85 | return true; 86 | } 87 | 88 | /** 89 | * to build a request url 90 | */ 91 | buildRequest (type, urlParams) { 92 | if (this.urlParams) { 93 | urlParams = this.urlParams.concat(urlParams); 94 | this.resetURLParams(); 95 | } 96 | 97 | const url = isArray(urlParams) ? this.makeUrl(...urlParams) : this.makeUrl(urlParams); 98 | 99 | return this.request(type, url); 100 | } 101 | 102 | /** 103 | * Make a GET request 104 | * 105 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 106 | */ 107 | get (...urlParams) { 108 | return this.buildRequest('get', urlParams); 109 | } 110 | 111 | /** 112 | * Make a POST request 113 | * 114 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 115 | */ 116 | post (...urlParams) { 117 | return this.buildRequest('post', urlParams); 118 | } 119 | 120 | /** 121 | * Make a PUT request 122 | * 123 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 124 | */ 125 | put (...urlParams) { 126 | return this.buildRequest('put', urlParams); 127 | } 128 | 129 | /** 130 | * Make a PATCH request 131 | * 132 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 133 | */ 134 | patch (...urlParams) { 135 | return this.buildRequest('patch', urlParams); 136 | } 137 | 138 | /** 139 | * Make a HEAD request 140 | * 141 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 142 | */ 143 | head (...urlParams) { 144 | return this.buildRequest('head', urlParams); 145 | } 146 | 147 | /** 148 | * Make a DELETE request 149 | * 150 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 151 | */ 152 | delete (...urlParams) { 153 | return this.buildRequest('delete', urlParams); 154 | } 155 | 156 | /** 157 | * Custom Routes 158 | * 159 | * These can be defined and passed via the customRoutes config attribute. 160 | * This allows you to completely override Rapid's usual functionality 161 | * and use this more like a router. 162 | */ 163 | 164 | /** 165 | * Make a request to a route via a given route name 166 | * The request type depends on the type of request defined in the route 167 | * 168 | * @param {string} name 169 | * @param {object} routeParams 170 | * @param {object} requestParams 171 | */ 172 | route (name = '', routeParams = {}, requestParams = {}) { 173 | const route = this.getCustomRoute(name, routeParams); 174 | 175 | // if there are request params, set them 176 | if (Object.keys(requestParams).length !== 0) { 177 | this.withParams(requestParams); 178 | } 179 | 180 | return this.request(route.type, route.url); 181 | } 182 | 183 | /** 184 | * Get a CustomRoute via given name 185 | * 186 | * @param {string} name 187 | * @param {object} routeParams 188 | */ 189 | getCustomRoute (name = '', routeParams = {}) { 190 | // if a route exists, return a new instance of CustomRoute 191 | if (Object.prototype.hasOwnProperty.call(this.customRoutes, name)) { 192 | return new CustomRoute(this.customRoutes[name], { 193 | routeParams, 194 | }); 195 | } 196 | 197 | // to prevent having undefined 198 | return new CustomRoute(); 199 | } 200 | 201 | /** 202 | * Generate a url to a custom defined route 203 | * 204 | * @param {string} name 205 | * @param {object} routeParams 206 | */ 207 | generate (name = '', routeParams = {}) { 208 | return this.getCustomRoute(name, routeParams).url; 209 | } 210 | 211 | /** 212 | * Before, after, and error 213 | */ 214 | 215 | /** 216 | * This is fired before the request 217 | */ 218 | beforeRequest (type, url) { 219 | return this.config.beforeRequest(type, url); 220 | } 221 | 222 | /** 223 | * This is fired after each request 224 | */ 225 | afterRequest (response) { 226 | this.resetRequestData(); 227 | this.config.afterRequest(response); 228 | } 229 | 230 | /** 231 | * This is fired on a request error 232 | */ 233 | onError (error) { 234 | this.resetRequestData(); 235 | this.config.onError(error); 236 | } 237 | 238 | /** 239 | * Params and Options 240 | */ 241 | 242 | /** 243 | * Send data and options with the request 244 | * 245 | * @param data An object of params: {}, options: {} 246 | */ 247 | withData (data = {}) { 248 | this.requestData = defaultsDeep(data, this.requestData); 249 | 250 | return this; 251 | } 252 | 253 | /** 254 | * Send params with the request 255 | * 256 | * @param params An object of params 257 | */ 258 | withParams (params = {}) { 259 | set(this.requestData, 'params', params); 260 | 261 | return this; 262 | } 263 | 264 | /** 265 | * Send a single param with the request 266 | * 267 | * @param key The key name 268 | * @param value The value 269 | */ 270 | withParam (key, value) { 271 | set(this.requestData, `params.${key}`, value); 272 | 273 | return this; 274 | } 275 | 276 | /** 277 | * Send options with the request 278 | * 279 | * @param options An object of options 280 | */ 281 | withOptions (options = {}) { 282 | set(this.requestData, 'options', options); 283 | 284 | return this; 285 | } 286 | 287 | /** 288 | * Send a single option with the request 289 | * 290 | * @param key The key name 291 | * @param value The value 292 | */ 293 | withOption (key, value) { 294 | set(this.requestData, `options.${key}`, value); 295 | 296 | return this; 297 | } 298 | } 299 | 300 | export default Request; 301 | -------------------------------------------------------------------------------- /src/core/request.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The Re-Quest to find the API 3 | */ 4 | 5 | import isArray from 'lodash/isArray'; 6 | import defaultsDeep from 'lodash/defaultsDeep'; 7 | import set from 'lodash/set'; 8 | import Routes from './routes'; 9 | import CustomRoute from './custom-route'; 10 | 11 | class Request extends Routes { 12 | constructor (config) { 13 | super(config); 14 | } 15 | 16 | /** 17 | * Parse the request data prior to passing it to axios 18 | * 19 | * @param type The request type 20 | */ 21 | parseRequestData (type) { 22 | const requestData = []; 23 | const { options } = this.requestData; 24 | let { params } = this.requestData; 25 | 26 | // axios handles the options differently for the request type 27 | if (['put', 'post', 'patch'].includes(type)) { 28 | params = defaultsDeep(params, this.config.globalParameters); 29 | requestData.push(params); 30 | requestData.push(options); 31 | } else { 32 | options.params = defaultsDeep(params, this.config.globalParameters); 33 | requestData.push(options); 34 | } 35 | 36 | return requestData; 37 | } 38 | 39 | /** 40 | * Make the request 41 | * 42 | * @param type The Request type 43 | * @param url The url 44 | */ 45 | request (type, url) { 46 | type = type.toLowerCase(); 47 | 48 | if (!this.isAllowedRequestType(type)) { 49 | return; 50 | } 51 | 52 | this.beforeRequest(type, url); 53 | 54 | if (this.config.debug) { 55 | return this.debugger.fakeRequest(type, url); 56 | } 57 | 58 | return new Promise((resolve, reject) => { 59 | this.api[type].call(this, this.sanitizeUrl(url), ...this.parseRequestData(type)) 60 | .then((response) => { 61 | this.afterRequest(response); 62 | 63 | resolve(response); 64 | }) 65 | .catch((error) => { 66 | this.onError(error); 67 | 68 | reject(error); 69 | }); 70 | }); 71 | } 72 | 73 | /** 74 | * Checks if is a valid request type 75 | * 76 | * @param type The request type 77 | */ 78 | isAllowedRequestType (type) { 79 | if (!this.config.allowedRequestTypes.includes(type)) { 80 | if (this.config.debug) { 81 | this.logger.warn(`'${type}' is not included in allowedRequestTypes: [${this.config.allowedRequestTypes.join(', ')}]`); 82 | } 83 | 84 | return false; 85 | } 86 | 87 | return true; 88 | } 89 | 90 | /** 91 | * to build a request url 92 | */ 93 | buildRequest (type, urlParams) { 94 | if (this.urlParams) { 95 | urlParams = this.urlParams.concat(urlParams); 96 | this.resetURLParams(); 97 | } 98 | 99 | const url = isArray(urlParams) ? this.makeUrl(...urlParams) : this.makeUrl(urlParams); 100 | 101 | return this.request(type, url); 102 | } 103 | 104 | /** 105 | * Make a GET request 106 | * 107 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 108 | */ 109 | get (...urlParams) { 110 | return this.buildRequest('get', urlParams); 111 | } 112 | 113 | /** 114 | * Make a POST request 115 | * 116 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 117 | */ 118 | post (...urlParams) { 119 | return this.buildRequest('post', urlParams); 120 | } 121 | 122 | /** 123 | * Make a PUT request 124 | * 125 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 126 | */ 127 | put (...urlParams) { 128 | return this.buildRequest('put', urlParams); 129 | } 130 | 131 | /** 132 | * Make a PATCH request 133 | * 134 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 135 | */ 136 | patch (...urlParams) { 137 | return this.buildRequest('patch', urlParams); 138 | } 139 | 140 | /** 141 | * Make a HEAD request 142 | * 143 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 144 | */ 145 | head (...urlParams) { 146 | return this.buildRequest('head', urlParams); 147 | } 148 | 149 | /** 150 | * Make a DELETE request 151 | * 152 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 153 | */ 154 | delete (...urlParams) { 155 | return this.buildRequest('delete', urlParams); 156 | } 157 | 158 | /** 159 | * Custom Routes 160 | * 161 | * These can be defined and passed via the customRoutes config attribute. 162 | * This allows you to completely override Rapid's usual functionality 163 | * and use this more like a router. 164 | */ 165 | 166 | /** 167 | * Make a request to a route via a given route name 168 | * The request type depends on the type of request defined in the route 169 | * 170 | * @param {string} name 171 | * @param {object} routeParams 172 | * @param {object} requestParams 173 | */ 174 | route (name = '', routeParams = {}, requestParams = {}) { 175 | const route = this.getCustomRoute(name, routeParams); 176 | 177 | // if there are request params, set them 178 | if (Object.keys(requestParams).length !== 0) { 179 | this.withParams(requestParams); 180 | } 181 | 182 | return this.request(route.type, route.url); 183 | } 184 | 185 | /** 186 | * Get a CustomRoute via given name 187 | * 188 | * @param {string} name 189 | * @param {object} routeParams 190 | */ 191 | getCustomRoute (name = '', routeParams = {}) { 192 | // if a route exists, return a new instance of CustomRoute 193 | if (Object.prototype.hasOwnProperty.call(this.customRoutes, name)) { 194 | return new CustomRoute(this.customRoutes[name], { 195 | routeParams, 196 | }); 197 | } 198 | 199 | // to prevent having undefined 200 | return new CustomRoute(); 201 | } 202 | 203 | /** 204 | * Generate a url to a custom defined route 205 | * This applies the baseURL and the trailing slash config 206 | * as well 207 | * 208 | * @param {string} name 209 | * @param {object} routeParams 210 | */ 211 | generate (name = '', routeParams = {}) { 212 | const { url } = this.getCustomRoute(name, routeParams); 213 | 214 | return url !== '' ? this.makeUrl(this.config.baseURL, url) : ''; 215 | } 216 | 217 | /** 218 | * Before, after, and error 219 | */ 220 | 221 | /** 222 | * This is fired before the request 223 | */ 224 | beforeRequest (type, url) { 225 | return this.config.beforeRequest(type, url); 226 | } 227 | 228 | /** 229 | * This is fired after each request 230 | */ 231 | afterRequest (response) { 232 | this.resetRequestData(); 233 | this.config.afterRequest(response); 234 | } 235 | 236 | /** 237 | * This is fired on a request error 238 | */ 239 | onError (error) { 240 | this.resetRequestData(); 241 | this.config.onError(error); 242 | } 243 | 244 | /** 245 | * Params and Options 246 | */ 247 | 248 | /** 249 | * Send data and options with the request 250 | * 251 | * @param data An object of params: {}, options: {} 252 | */ 253 | withData (data = {}) { 254 | this.requestData = defaultsDeep(data, this.requestData); 255 | 256 | return this; 257 | } 258 | 259 | /** 260 | * Send params with the request 261 | * 262 | * @param params An object of params 263 | */ 264 | withParams (params = {}) { 265 | set(this.requestData, 'params', params); 266 | 267 | return this; 268 | } 269 | 270 | /** 271 | * Send a single param with the request 272 | * 273 | * @param key The key name 274 | * @param value The value 275 | */ 276 | withParam (key, value) { 277 | set(this.requestData, `params.${key}`, value); 278 | 279 | return this; 280 | } 281 | 282 | /** 283 | * Send options with the request 284 | * 285 | * @param options An object of options 286 | */ 287 | withOptions (options = {}) { 288 | set(this.requestData, 'options', options); 289 | 290 | return this; 291 | } 292 | 293 | /** 294 | * Send a single option with the request 295 | * 296 | * @param key The key name 297 | * @param value The value 298 | */ 299 | withOption (key, value) { 300 | set(this.requestData, `options.${key}`, value); 301 | 302 | return this; 303 | } 304 | } 305 | 306 | export default Request; 307 | -------------------------------------------------------------------------------- /demo/webpack.config.js: -------------------------------------------------------------------------------- 1 | let path = require('path'); 2 | let glob = require('glob'); 3 | let webpack = require('webpack'); 4 | let Mix = require('laravel-mix').config; 5 | let webpackPlugins = require('laravel-mix').plugins; 6 | 7 | /* 8 | |-------------------------------------------------------------------------- 9 | | Mix Initialization 10 | |-------------------------------------------------------------------------- 11 | | 12 | | As our first step, we'll require the project's Laravel Mix file 13 | | and record the user's requested compilation and build steps. 14 | | Once those steps have been recorded, we may get to work. 15 | | 16 | */ 17 | 18 | Mix.initialize(); 19 | 20 | 21 | 22 | /* 23 | |-------------------------------------------------------------------------- 24 | | Webpack Context 25 | |-------------------------------------------------------------------------- 26 | | 27 | | This prop will determine the appropriate context, when running Webpack. 28 | | Since you have the option of publishing this webpack.config.js file 29 | | to your project root, we will dynamically set the path for you. 30 | | 31 | */ 32 | 33 | module.exports.context = Mix.Paths.root(); 34 | 35 | 36 | 37 | /* 38 | |-------------------------------------------------------------------------- 39 | | Webpack Entry 40 | |-------------------------------------------------------------------------- 41 | | 42 | | We'll first specify the entry point for Webpack. By default, we'll 43 | | assume a single bundled file, but you may call Mix.extract() 44 | | to make a separate bundle specifically for vendor libraries. 45 | | 46 | */ 47 | 48 | module.exports.entry = Mix.entry().get(); 49 | 50 | 51 | 52 | /* 53 | |-------------------------------------------------------------------------- 54 | | Webpack Output 55 | |-------------------------------------------------------------------------- 56 | | 57 | | Webpack naturally requires us to specify our desired output path and 58 | | file name. We'll simply echo what you passed to with Mix.js(). 59 | | Note that, for Mix.version(), we'll properly hash the file. 60 | | 61 | */ 62 | 63 | module.exports.output = Mix.output(); 64 | 65 | 66 | 67 | /* 68 | |-------------------------------------------------------------------------- 69 | | Rules 70 | |-------------------------------------------------------------------------- 71 | | 72 | | Webpack rules allow us to register any number of loaders and options. 73 | | Out of the box, we'll provide a handful to get you up and running 74 | | as quickly as possible, though feel free to add to this list. 75 | | 76 | */ 77 | 78 | let plugins = []; 79 | 80 | if (Mix.options.extractVueStyles) { 81 | var vueExtractTextPlugin = Mix.vueExtractTextPlugin(); 82 | 83 | plugins.push(vueExtractTextPlugin); 84 | } 85 | 86 | let rules = [ 87 | { 88 | test: /\.vue$/, 89 | loader: 'vue-loader', 90 | options: { 91 | loaders: Mix.options.extractVueStyles ? { 92 | js: 'babel-loader' + Mix.babelConfig(), 93 | scss: vueExtractTextPlugin.extract({ 94 | use: 'css-loader!sass-loader', 95 | fallback: 'vue-style-loader' 96 | }), 97 | sass: vueExtractTextPlugin.extract({ 98 | use: 'css-loader!sass-loader?indentedSyntax', 99 | fallback: 'vue-style-loader' 100 | }), 101 | stylus: vueExtractTextPlugin.extract({ 102 | use: 'css-loader!stylus-loader?paths[]=node_modules', 103 | fallback: 'vue-style-loader' 104 | }), 105 | css: vueExtractTextPlugin.extract({ 106 | use: 'css-loader', 107 | fallback: 'vue-style-loader' 108 | }) 109 | }: { 110 | js: 'babel-loader' + Mix.babelConfig(), 111 | scss: 'vue-style-loader!css-loader!sass-loader', 112 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax', 113 | stylus: 'vue-style-loader!css-loader!stylus-loader?paths[]=node_modules' 114 | }, 115 | 116 | postcss: Mix.options.postCss 117 | } 118 | }, 119 | 120 | { 121 | test: /\.jsx?$/, 122 | exclude: /(node_modules|bower_components)/, 123 | loader: 'babel-loader' + Mix.babelConfig() 124 | }, 125 | 126 | { 127 | test: /\.css$/, 128 | loaders: ['style-loader', 'css-loader'] 129 | }, 130 | 131 | { 132 | test: /\.s[ac]ss$/, 133 | include: /node_modules/, 134 | loaders: ['style-loader', 'css-loader', 'sass-loader'] 135 | }, 136 | 137 | { 138 | test: /\.html$/, 139 | loaders: ['html-loader'] 140 | }, 141 | 142 | { 143 | test: /\.(png|jpe?g|gif)$/, 144 | loaders: [ 145 | { 146 | loader: 'file-loader', 147 | options: { 148 | name: path => { 149 | if (! /node_modules|bower_components/.test(path)) { 150 | return 'images/[name].[ext]?[hash]'; 151 | } 152 | 153 | return 'images/vendor/' + path 154 | .replace(/\\/g, '/') 155 | .replace( 156 | /((.*(node_modules|bower_components))|images|image|img|assets)\//g, '' 157 | ) + '?[hash]'; 158 | }, 159 | publicPath: Mix.options.resourceRoot 160 | } 161 | }, 162 | 'img-loader' 163 | ] 164 | }, 165 | 166 | { 167 | test: /\.(woff2?|ttf|eot|svg|otf)$/, 168 | loader: 'file-loader', 169 | options: { 170 | name: path => { 171 | if (! /node_modules|bower_components/.test(path)) { 172 | return 'fonts/[name].[ext]?[hash]'; 173 | } 174 | 175 | return 'fonts/vendor/' + path 176 | .replace(/\\/g, '/') 177 | .replace( 178 | /((.*(node_modules|bower_components))|fonts|font|assets)\//g, '' 179 | ) + '?[hash]'; 180 | }, 181 | publicPath: Mix.options.resourceRoot 182 | } 183 | }, 184 | 185 | { 186 | test: /\.(cur|ani)$/, 187 | loader: 'file-loader', 188 | options: { 189 | name: '[name].[ext]?[hash]', 190 | publicPath: Mix.options.resourceRoot 191 | } 192 | } 193 | ]; 194 | 195 | if (Mix.preprocessors) { 196 | Mix.preprocessors.forEach(preprocessor => { 197 | rules.push(preprocessor.rules()); 198 | 199 | plugins.push(preprocessor.extractPlugin); 200 | }); 201 | } 202 | 203 | module.exports.module = { rules }; 204 | 205 | 206 | 207 | /* 208 | |-------------------------------------------------------------------------- 209 | | Resolve 210 | |-------------------------------------------------------------------------- 211 | | 212 | | Here, we may set any options/aliases that affect Webpack's resolving 213 | | of modules. To begin, we will provide the necessary Vue alias to 214 | | load the Vue common library. You may delete this, if needed. 215 | | 216 | */ 217 | 218 | module.exports.resolve = { 219 | extensions: ['*', '.js', '.jsx', '.vue'], 220 | 221 | alias: { 222 | 'vue$': 'vue/dist/vue.common.js' 223 | } 224 | }; 225 | 226 | 227 | 228 | /* 229 | |-------------------------------------------------------------------------- 230 | | Stats 231 | |-------------------------------------------------------------------------- 232 | | 233 | | By default, Webpack spits a lot of information out to the terminal, 234 | | each you time you compile. Let's keep things a bit more minimal 235 | | and hide a few of those bits and pieces. Adjust as you wish. 236 | | 237 | */ 238 | 239 | module.exports.stats = { 240 | hash: false, 241 | version: false, 242 | timings: false, 243 | children: false, 244 | errors: false 245 | }; 246 | 247 | process.noDeprecation = true; 248 | 249 | module.exports.performance = { hints: false }; 250 | 251 | 252 | 253 | /* 254 | |-------------------------------------------------------------------------- 255 | | Devtool 256 | |-------------------------------------------------------------------------- 257 | | 258 | | Sourcemaps allow us to access our original source code within the 259 | | browser, even if we're serving a bundled script or stylesheet. 260 | | You may activate sourcemaps, by adding Mix.sourceMaps(). 261 | | 262 | */ 263 | 264 | module.exports.devtool = Mix.options.sourcemaps; 265 | 266 | 267 | 268 | /* 269 | |-------------------------------------------------------------------------- 270 | | Webpack Dev Server Configuration 271 | |-------------------------------------------------------------------------- 272 | | 273 | | If you want to use that flashy hot module replacement feature, then 274 | | we've got you covered. Here, we'll set some basic initial config 275 | | for the Node server. You very likely won't want to edit this. 276 | | 277 | */ 278 | module.exports.devServer = { 279 | historyApiFallback: true, 280 | noInfo: true, 281 | compress: true, 282 | quiet: true 283 | }; 284 | 285 | 286 | 287 | /* 288 | |-------------------------------------------------------------------------- 289 | | Plugins 290 | |-------------------------------------------------------------------------- 291 | | 292 | | Lastly, we'll register a number of plugins to extend and configure 293 | | Webpack. To get you started, we've included a handful of useful 294 | | extensions, for versioning, OS notifications, and much more. 295 | | 296 | */ 297 | 298 | plugins.push( 299 | new webpack.ProvidePlugin(Mix.autoload || {}), 300 | 301 | new webpackPlugins.FriendlyErrorsWebpackPlugin({ clearConsole: Mix.options.clearConsole }), 302 | 303 | new webpackPlugins.StatsWriterPlugin({ 304 | filename: 'mix-manifest.json', 305 | transform: Mix.manifest.transform.bind(Mix.manifest), 306 | }), 307 | 308 | new webpack.LoaderOptionsPlugin({ 309 | minimize: Mix.inProduction, 310 | options: { 311 | postcss: Mix.options.postCss, 312 | context: __dirname, 313 | output: { path: './' } 314 | } 315 | }) 316 | ); 317 | 318 | if (Mix.browserSync) { 319 | plugins.push( 320 | new webpackPlugins.BrowserSyncPlugin( 321 | Object.assign({ 322 | host: 'localhost', 323 | port: 3000, 324 | proxy: 'app.dev', 325 | files: [ 326 | 'app/**/*.php', 327 | 'resources/views/**/*.php', 328 | 'public/js/**/*.js', 329 | 'public/css/**/*.css' 330 | ] 331 | }, Mix.browserSync), 332 | { 333 | reload: false 334 | } 335 | ) 336 | ); 337 | } 338 | 339 | if (Mix.options.notifications) { 340 | plugins.push( 341 | new webpackPlugins.WebpackNotifierPlugin({ 342 | title: 'Laravel Mix', 343 | alwaysNotify: true, 344 | contentImage: Mix.Paths.root('node_modules/laravel-mix/icons/laravel.png') 345 | }) 346 | ); 347 | } 348 | 349 | if (Mix.copy) { 350 | Mix.copy.forEach(copy => { 351 | plugins.push( 352 | new webpackPlugins.CopyWebpackPlugin([copy]) 353 | ); 354 | }); 355 | } 356 | 357 | if (Mix.entry().hasExtractions()) { 358 | plugins.push( 359 | new webpack.optimize.CommonsChunkPlugin({ 360 | names: Mix.entry().getExtractions(), 361 | minChunks: Infinity 362 | }) 363 | ); 364 | } 365 | 366 | if (Mix.options.versioning) { 367 | plugins.push( 368 | new webpack[Mix.inProduction ? 'HashedModuleIdsPlugin': 'NamedModulesPlugin'](), 369 | new webpackPlugins.WebpackChunkHashPlugin() 370 | ); 371 | } 372 | 373 | if (Mix.options.purifyCss) { 374 | let PurifyCSSPlugin = require('purifycss-webpack'); 375 | 376 | // By default, we'll scan all Blade and Vue files in our project. 377 | let paths = glob.sync(Mix.Paths.root('resources/views/**/*.blade.php')).concat( 378 | Mix.entry().scripts.reduce((carry, js) => { 379 | return carry.concat(glob.sync(js.base + '/**/*.vue')); 380 | }, []) 381 | ); 382 | 383 | plugins.push(new PurifyCSSPlugin( 384 | Object.assign({ paths }, Mix.options.purifyCss, { minimize: Mix.inProduction }) 385 | )); 386 | } 387 | 388 | if (Mix.inProduction) { 389 | plugins.push( 390 | new webpack.DefinePlugin({ 391 | 'process.env': { 392 | NODE_ENV: '"production"' 393 | } 394 | }) 395 | ); 396 | 397 | if (Mix.options.uglify) { 398 | plugins.push( 399 | new webpack.optimize.UglifyJsPlugin(Mix.options.uglify) 400 | ); 401 | } 402 | } 403 | 404 | plugins.push( 405 | new webpackPlugins.WebpackOnBuildPlugin( 406 | stats => global.events.fire('build', stats) 407 | ) 408 | ); 409 | 410 | if (! Mix.entry().hasScripts()) { 411 | plugins.push(new webpackPlugins.MockEntryPlugin(Mix.output().path)); 412 | } 413 | 414 | module.exports.plugins = plugins; 415 | 416 | 417 | 418 | /* 419 | |-------------------------------------------------------------------------- 420 | | Mix Finalizing 421 | |-------------------------------------------------------------------------- 422 | | 423 | | Now that we've declared the entirety of our Webpack configuration, the 424 | | final step is to scan for any custom configuration in the Mix file. 425 | | If mix.webpackConfig() is called, we'll merge it in, and build! 426 | | 427 | */ 428 | 429 | if (Mix.webpackConfig) { 430 | module.exports = require('webpack-merge').smart( 431 | module.exports, Mix.webpackConfig 432 | ); 433 | } 434 | -------------------------------------------------------------------------------- /dist/core/request.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _isArray = require('lodash/isArray'); 10 | 11 | var _isArray2 = _interopRequireDefault(_isArray); 12 | 13 | var _defaultsDeep = require('lodash/defaultsDeep'); 14 | 15 | var _defaultsDeep2 = _interopRequireDefault(_defaultsDeep); 16 | 17 | var _set = require('lodash/set'); 18 | 19 | var _set2 = _interopRequireDefault(_set); 20 | 21 | var _routes = require('./routes'); 22 | 23 | var _routes2 = _interopRequireDefault(_routes); 24 | 25 | var _customRoute = require('./custom-route'); 26 | 27 | var _customRoute2 = _interopRequireDefault(_customRoute); 28 | 29 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 30 | 31 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } 32 | 33 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 34 | 35 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 36 | 37 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** 38 | * The Re-Quest to find the API 39 | */ 40 | 41 | var Request = function (_Routes) { 42 | _inherits(Request, _Routes); 43 | 44 | function Request(config) { 45 | _classCallCheck(this, Request); 46 | 47 | return _possibleConstructorReturn(this, (Request.__proto__ || Object.getPrototypeOf(Request)).call(this, config)); 48 | } 49 | 50 | /** 51 | * Parse the request data prior to passing it to axios 52 | * 53 | * @param type The request type 54 | */ 55 | 56 | 57 | _createClass(Request, [{ 58 | key: 'parseRequestData', 59 | value: function parseRequestData(type) { 60 | var requestData = []; 61 | var options = this.requestData.options; 62 | var params = this.requestData.params; 63 | 64 | // axios handles the options differently for the request type 65 | 66 | if (['put', 'post', 'patch'].includes(type)) { 67 | params = (0, _defaultsDeep2.default)(params, this.config.globalParameters); 68 | requestData.push(params); 69 | requestData.push(options); 70 | } else { 71 | options.params = (0, _defaultsDeep2.default)(params, this.config.globalParameters); 72 | requestData.push(options); 73 | } 74 | 75 | return requestData; 76 | } 77 | 78 | /** 79 | * Make the request 80 | * 81 | * @param type The Request type 82 | * @param url The url 83 | */ 84 | 85 | }, { 86 | key: 'request', 87 | value: function request(type, url) { 88 | var _this2 = this; 89 | 90 | type = type.toLowerCase(); 91 | 92 | if (!this.isAllowedRequestType(type)) { 93 | return; 94 | } 95 | 96 | this.beforeRequest(type, url); 97 | 98 | if (this.config.debug) { 99 | return this.debugger.fakeRequest(type, url); 100 | } 101 | 102 | return new Promise(function (resolve, reject) { 103 | var _api$type; 104 | 105 | (_api$type = _this2.api[type]).call.apply(_api$type, [_this2, _this2.sanitizeUrl(url)].concat(_toConsumableArray(_this2.parseRequestData(type)))).then(function (response) { 106 | _this2.afterRequest(response); 107 | 108 | resolve(response); 109 | }).catch(function (error) { 110 | _this2.onError(error); 111 | 112 | reject(error); 113 | }); 114 | }); 115 | } 116 | 117 | /** 118 | * Checks if is a valid request type 119 | * 120 | * @param type The request type 121 | */ 122 | 123 | }, { 124 | key: 'isAllowedRequestType', 125 | value: function isAllowedRequestType(type) { 126 | if (!this.config.allowedRequestTypes.includes(type)) { 127 | if (this.config.debug) { 128 | this.logger.warn('\'' + type + '\' is not included in allowedRequestTypes: [' + this.config.allowedRequestTypes.join(', ') + ']'); 129 | } 130 | 131 | return false; 132 | } 133 | 134 | return true; 135 | } 136 | 137 | /** 138 | * to build a request url 139 | */ 140 | 141 | }, { 142 | key: 'buildRequest', 143 | value: function buildRequest(type, urlParams) { 144 | if (this.urlParams) { 145 | urlParams = this.urlParams.concat(urlParams); 146 | this.resetURLParams(); 147 | } 148 | 149 | var url = (0, _isArray2.default)(urlParams) ? this.makeUrl.apply(this, _toConsumableArray(urlParams)) : this.makeUrl(urlParams); 150 | 151 | return this.request(type, url); 152 | } 153 | 154 | /** 155 | * Make a GET request 156 | * 157 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 158 | */ 159 | 160 | }, { 161 | key: 'get', 162 | value: function get() { 163 | for (var _len = arguments.length, urlParams = Array(_len), _key = 0; _key < _len; _key++) { 164 | urlParams[_key] = arguments[_key]; 165 | } 166 | 167 | return this.buildRequest('get', urlParams); 168 | } 169 | 170 | /** 171 | * Make a POST request 172 | * 173 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 174 | */ 175 | 176 | }, { 177 | key: 'post', 178 | value: function post() { 179 | for (var _len2 = arguments.length, urlParams = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 180 | urlParams[_key2] = arguments[_key2]; 181 | } 182 | 183 | return this.buildRequest('post', urlParams); 184 | } 185 | 186 | /** 187 | * Make a PUT request 188 | * 189 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 190 | */ 191 | 192 | }, { 193 | key: 'put', 194 | value: function put() { 195 | for (var _len3 = arguments.length, urlParams = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { 196 | urlParams[_key3] = arguments[_key3]; 197 | } 198 | 199 | return this.buildRequest('put', urlParams); 200 | } 201 | 202 | /** 203 | * Make a PATCH request 204 | * 205 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 206 | */ 207 | 208 | }, { 209 | key: 'patch', 210 | value: function patch() { 211 | for (var _len4 = arguments.length, urlParams = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { 212 | urlParams[_key4] = arguments[_key4]; 213 | } 214 | 215 | return this.buildRequest('patch', urlParams); 216 | } 217 | 218 | /** 219 | * Make a HEAD request 220 | * 221 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 222 | */ 223 | 224 | }, { 225 | key: 'head', 226 | value: function head() { 227 | for (var _len5 = arguments.length, urlParams = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { 228 | urlParams[_key5] = arguments[_key5]; 229 | } 230 | 231 | return this.buildRequest('head', urlParams); 232 | } 233 | 234 | /** 235 | * Make a DELETE request 236 | * 237 | * @param urlParams The url params to be concatenated to the urlParams (See buildRequest) 238 | */ 239 | 240 | }, { 241 | key: 'delete', 242 | value: function _delete() { 243 | for (var _len6 = arguments.length, urlParams = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { 244 | urlParams[_key6] = arguments[_key6]; 245 | } 246 | 247 | return this.buildRequest('delete', urlParams); 248 | } 249 | 250 | /** 251 | * Custom Routes 252 | * 253 | * These can be defined and passed via the customRoutes config attribute. 254 | * This allows you to completely override Rapid's usual functionality 255 | * and use this more like a router. 256 | */ 257 | 258 | /** 259 | * Make a request to a route via a given route name 260 | * The request type depends on the type of request defined in the route 261 | * 262 | * @param {string} name 263 | * @param {object} routeParams 264 | * @param {object} requestParams 265 | */ 266 | 267 | }, { 268 | key: 'route', 269 | value: function route() { 270 | var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; 271 | var routeParams = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 272 | var requestParams = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; 273 | 274 | var route = this.getCustomRoute(name, routeParams); 275 | 276 | // if there are request params, set them 277 | if (Object.keys(requestParams).length !== 0) { 278 | this.withParams(requestParams); 279 | } 280 | 281 | return this.request(route.type, route.url); 282 | } 283 | 284 | /** 285 | * Get a CustomRoute via given name 286 | * 287 | * @param {string} name 288 | * @param {object} routeParams 289 | */ 290 | 291 | }, { 292 | key: 'getCustomRoute', 293 | value: function getCustomRoute() { 294 | var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; 295 | var routeParams = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 296 | 297 | // if a route exists, return a new instance of CustomRoute 298 | if (Object.prototype.hasOwnProperty.call(this.customRoutes, name)) { 299 | return new _customRoute2.default(this.customRoutes[name], { 300 | routeParams: routeParams 301 | }); 302 | } 303 | 304 | // to prevent having undefined 305 | return new _customRoute2.default(); 306 | } 307 | 308 | /** 309 | * Generate a url to a custom defined route 310 | * This applies the baseURL and the trailing slash config 311 | * as well 312 | * 313 | * @param {string} name 314 | * @param {object} routeParams 315 | */ 316 | 317 | }, { 318 | key: 'generate', 319 | value: function generate() { 320 | var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; 321 | var routeParams = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 322 | 323 | var _getCustomRoute = this.getCustomRoute(name, routeParams), 324 | url = _getCustomRoute.url; 325 | 326 | return url !== '' ? this.makeUrl(this.config.baseURL, url) : ''; 327 | } 328 | 329 | /** 330 | * Before, after, and error 331 | */ 332 | 333 | /** 334 | * This is fired before the request 335 | */ 336 | 337 | }, { 338 | key: 'beforeRequest', 339 | value: function beforeRequest(type, url) { 340 | return this.config.beforeRequest(type, url); 341 | } 342 | 343 | /** 344 | * This is fired after each request 345 | */ 346 | 347 | }, { 348 | key: 'afterRequest', 349 | value: function afterRequest(response) { 350 | this.resetRequestData(); 351 | this.config.afterRequest(response); 352 | } 353 | 354 | /** 355 | * This is fired on a request error 356 | */ 357 | 358 | }, { 359 | key: 'onError', 360 | value: function onError(error) { 361 | this.resetRequestData(); 362 | this.config.onError(error); 363 | } 364 | 365 | /** 366 | * Params and Options 367 | */ 368 | 369 | /** 370 | * Send data and options with the request 371 | * 372 | * @param data An object of params: {}, options: {} 373 | */ 374 | 375 | }, { 376 | key: 'withData', 377 | value: function withData() { 378 | var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 379 | 380 | this.requestData = (0, _defaultsDeep2.default)(data, this.requestData); 381 | 382 | return this; 383 | } 384 | 385 | /** 386 | * Send params with the request 387 | * 388 | * @param params An object of params 389 | */ 390 | 391 | }, { 392 | key: 'withParams', 393 | value: function withParams() { 394 | var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 395 | 396 | (0, _set2.default)(this.requestData, 'params', params); 397 | 398 | return this; 399 | } 400 | 401 | /** 402 | * Send a single param with the request 403 | * 404 | * @param key The key name 405 | * @param value The value 406 | */ 407 | 408 | }, { 409 | key: 'withParam', 410 | value: function withParam(key, value) { 411 | (0, _set2.default)(this.requestData, 'params.' + key, value); 412 | 413 | return this; 414 | } 415 | 416 | /** 417 | * Send options with the request 418 | * 419 | * @param options An object of options 420 | */ 421 | 422 | }, { 423 | key: 'withOptions', 424 | value: function withOptions() { 425 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 426 | 427 | (0, _set2.default)(this.requestData, 'options', options); 428 | 429 | return this; 430 | } 431 | 432 | /** 433 | * Send a single option with the request 434 | * 435 | * @param key The key name 436 | * @param value The value 437 | */ 438 | 439 | }, { 440 | key: 'withOption', 441 | value: function withOption(key, value) { 442 | (0, _set2.default)(this.requestData, 'options.' + key, value); 443 | 444 | return this; 445 | } 446 | }]); 447 | 448 | return Request; 449 | }(_routes2.default); 450 | 451 | exports.default = Request; --------------------------------------------------------------------------------