├── static ├── favicon.ico └── README.md ├── api ├── index.js ├── users.js └── auth.js ├── utils ├── getProperty.js ├── transition │ └── beforeEnter.js ├── throttle.js ├── vue-router │ └── scrollBehavior.js └── mailProviders.js ├── plugins ├── vuetify.js ├── README.md └── veeValidate.js ├── .gitignore ├── components ├── README.md └── auth │ ├── LogoutForm.vue │ ├── VerifyEmailDialog.vue │ ├── PasswordResetForm.vue │ ├── LoginForm.vue │ ├── PasswordResetConfirmForm.vue │ ├── PasswordChangeForm.vue │ ├── RegistrationForm.vue │ └── UserEditForm.vue ├── .editorconfig ├── layouts ├── README.md ├── default.vue ├── error.vue └── baseLayout.vue ├── middleware ├── user-agent.js └── README.md ├── pages ├── README.md ├── auth │ ├── logout │ │ └── index.vue │ ├── user │ │ └── edit │ │ │ └── index.vue │ ├── login │ │ └── index.vue │ ├── password │ │ ├── reset │ │ │ ├── index.vue │ │ │ └── confirm │ │ │ │ └── _uid │ │ │ │ └── _token │ │ │ │ └── index.vue │ │ └── change │ │ │ └── index.vue │ └── registration │ │ ├── confirm-email │ │ └── _key.vue │ │ └── index.vue ├── index.vue ├── settings │ └── index.vue └── users │ ├── _id.vue │ └── index.vue ├── assets ├── README.md └── style │ └── app.styl ├── store ├── README.md ├── index.js ├── auth.js ├── users.js └── settings.js ├── modules └── @nuxtjs │ ├── auth │ ├── templates │ │ ├── auth.middleware.js │ │ ├── auth.plugin.js │ │ └── auth.store.js │ ├── src │ │ └── index.js │ ├── LICENSE │ ├── package.json │ ├── CHANGELOG.md │ ├── README.md │ └── lib │ │ └── index.js │ └── axios │ ├── LICENSE │ ├── package.json │ ├── lib │ ├── index.js │ └── plugin.template.js │ ├── CHANGELOG.md │ └── README.md ├── README.md ├── .eslintrc.js ├── package.json └── nuxt.config.js /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbikbov/nuxt-drf-frontend/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /api/index.js: -------------------------------------------------------------------------------- 1 | import * as auth from './auth'; 2 | import * as users from './users'; 3 | 4 | export { auth, users }; 5 | -------------------------------------------------------------------------------- /utils/getProperty.js: -------------------------------------------------------------------------------- 1 | export default (obj, prop) => 2 | prop 3 | .split('.') 4 | .reduce((m, i) => (m && typeof m === 'object' ? m[i] : m), obj); 5 | -------------------------------------------------------------------------------- /utils/transition/beforeEnter.js: -------------------------------------------------------------------------------- 1 | module.exports = function(el) { 2 | // global.console.log('Before enter...', el); 3 | }; 4 | 5 | // module.exports = beforeEnter; 6 | -------------------------------------------------------------------------------- /plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-extraneous-dependencies 2 | import Vue from 'vue'; 3 | import Vuetify from 'vuetify'; 4 | 5 | Vue.use(Vuetify); 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules 3 | 4 | # logs 5 | npm-debug.log 6 | 7 | # Nuxt build 8 | .nuxt 9 | 10 | # Nuxt generate 11 | dist 12 | 13 | .vscode 14 | 15 | components/chat -------------------------------------------------------------------------------- /components/README.md: -------------------------------------------------------------------------------- 1 | # COMPONENTS 2 | 3 | The components directory contains your Vue.js Components. 4 | Nuxt.js doesn't supercharge these components. 5 | 6 | **This directory is not required, you can delete it if you don't want to use it.** 7 | -------------------------------------------------------------------------------- /api/users.js: -------------------------------------------------------------------------------- 1 | export const fetchUsers = ({ endpoint, params }) => ({ 2 | method: 'get', 3 | url: endpoint || 'users/', 4 | params 5 | }); 6 | 7 | export const fetchUser = ({ id }) => ({ 8 | method: 'get', 9 | url: `users/${id}` 10 | }); 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /utils/throttle.js: -------------------------------------------------------------------------------- 1 | export default (callback, limit) => { 2 | let wait = false; 3 | return () => { 4 | if (!wait) { 5 | wait = true; 6 | setTimeout(() => { 7 | wait = false; 8 | callback.call(); 9 | }, limit); 10 | } 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /layouts/README.md: -------------------------------------------------------------------------------- 1 | # LAYOUTS 2 | 3 | This directory contains your Application Layouts. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/views#layouts 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /layouts/default.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | -------------------------------------------------------------------------------- /middleware/user-agent.js: -------------------------------------------------------------------------------- 1 | export default function(context) { 2 | // Add the userAgent property in the context (available in `data` and `fetch`) 3 | context.userAgent = context.isServer 4 | ? context.req.headers['user-agent'] 5 | : navigator.userAgent; 6 | // global.console.log(context.userAgent); 7 | } 8 | -------------------------------------------------------------------------------- /pages/README.md: -------------------------------------------------------------------------------- 1 | # PAGES 2 | 3 | This directory contains your Application Views and Routes. 4 | The framework reads all the .vue files inside this directory and create the router of your application. 5 | 6 | More information about the usage of this directory in the documentation: 7 | https://nuxtjs.org/guide/routing 8 | -------------------------------------------------------------------------------- /assets/README.md: -------------------------------------------------------------------------------- 1 | # ASSETS 2 | 3 | This directory contains your un-compiled assets such as LESS, SASS, or JavaScript. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/assets#webpacked 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /plugins/README.md: -------------------------------------------------------------------------------- 1 | # PLUGINS 2 | 3 | This directory contains your Javascript plugins that you want to run before instantiating the root vue.js application. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/plugins 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /components/auth/LogoutForm.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | -------------------------------------------------------------------------------- /static/README.md: -------------------------------------------------------------------------------- 1 | # STATIC 2 | 3 | This directory contains your static files. 4 | Each file inside this directory is mapped to /. 5 | 6 | Example: /static/robots.txt is mapped as /robots.txt. 7 | 8 | More information about the usage of this directory in the documentation: 9 | https://nuxtjs.org/guide/assets#static 10 | 11 | **This directory is not required, you can delete it if you don't want to use it.** 12 | -------------------------------------------------------------------------------- /assets/style/app.styl: -------------------------------------------------------------------------------- 1 | // Specify overrides (theme and/or base variables etc.) 2 | // See https://vuetifyjs.com/quick-start 3 | $theme := { 4 | primary: #9c27b0 5 | accent: #ce93d8 6 | secondary: #424242 7 | info: #0D47A1 8 | warning: #ffb300 9 | error: #B71C1C 10 | success: #2E7D32 11 | } 12 | 13 | // Import Vuetify styling 14 | @require '~vuetify/src/stylus/main.styl' 15 | 16 | .page 17 | @extend .fade-transition -------------------------------------------------------------------------------- /middleware/README.md: -------------------------------------------------------------------------------- 1 | # MIDDLEWARE 2 | 3 | This directory contains your Application Middleware. 4 | The middleware lets you define custom function to be ran before rendering a page or a group of pages (layouts). 5 | 6 | More information about the usage of this directory in the documentation: 7 | https://nuxtjs.org/guide/routing#middleware 8 | 9 | **This directory is not required, you can delete it if you don't want to use it.** 10 | -------------------------------------------------------------------------------- /pages/auth/logout/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | -------------------------------------------------------------------------------- /store/README.md: -------------------------------------------------------------------------------- 1 | # STORE 2 | 3 | This directory contains your Vuex Store files. 4 | Vuex Store option is implemented in the Nuxt.js framework. 5 | Creating a index.js file in this directory activate the option in the framework automatically. 6 | 7 | More information about the usage of this directory in the documentation: 8 | https://nuxtjs.org/guide/vuex-store 9 | 10 | **This directory is not required, you can delete it if you don't want to use it.** 11 | -------------------------------------------------------------------------------- /layouts/error.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /modules/@nuxtjs/auth/templates/auth.middleware.js: -------------------------------------------------------------------------------- 1 | import middleware from './middleware'; 2 | 3 | middleware.auth = function authMiddleware({ store, redirect }) { 4 | // If user not logged in, redirect to /login 5 | if (!store.getters['auth/loggedIn']) { 6 | return redirect('/auth/login'); 7 | } 8 | }; 9 | 10 | middleware['no-auth'] = function noAuthMiddleware({ store, redirect }) { 11 | // If user is already logged in, redirect to / 12 | if (store.getters['auth/loggedIn']) { 13 | return redirect('/'); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nuxt-drf 2 | 3 | > Nuxt.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | $ npm install # Or yarn install 10 | 11 | # serve with hot reload at localhost:3000 12 | $ npm run dev 13 | 14 | # build for production and launch server 15 | $ npm run build 16 | $ npm start 17 | 18 | # generate static project 19 | $ npm run generate 20 | ``` 21 | 22 | For detailed explanation on how things work, checkout the [Nuxt.js docs](https://github.com/nuxt/nuxt.js). 23 | 24 | Backend (Django REST Framework) (https://github.com/rafizz/nuxt-drf-backend). 25 | -------------------------------------------------------------------------------- /modules/@nuxtjs/auth/src/index.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path') 2 | 3 | export default async function module (moduleOptions) { 4 | // const options = Object.assign({}, this.options.auth, moduleOptions) 5 | 6 | // Plugin 7 | this.addPlugin({ src: resolve(__dirname, '../templates/auth.plugin.js'), fileName: 'auth.plugin.js' }) 8 | 9 | // Middleware 10 | this.addTemplate({ src: resolve(__dirname, '../templates/auth.middleware.js'), fileName: 'auth.middleware.js' }) 11 | 12 | // Store 13 | this.addTemplate({ src: resolve(__dirname, '../templates/auth.store.js'), fileName: 'auth.store.js' }) 14 | } 15 | -------------------------------------------------------------------------------- /pages/auth/user/edit/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 28 | -------------------------------------------------------------------------------- /store/index.js: -------------------------------------------------------------------------------- 1 | export const state = () => ({}); 2 | 3 | export const actions = { 4 | // nuxtServerInit is called by Nuxt.js before server-rendering every page 5 | // nuxtServerInit( 6 | // { dispatch, commit, getters, state, rootGetters, rootState }, 7 | // { 8 | // isServer, 9 | // isClient, 10 | // isStatic, 11 | // isDev, 12 | // isHMR, 13 | // app, 14 | // store, 15 | // error, 16 | // env, 17 | // redirect, 18 | // req, 19 | // res 20 | // } 21 | // ) { 22 | // if (req.session && req.session.authUser) { 23 | // commit('SET_USER', req.session.authUser); 24 | // } 25 | // } 26 | }; 27 | -------------------------------------------------------------------------------- /modules/@nuxtjs/auth/templates/auth.plugin.js: -------------------------------------------------------------------------------- 1 | import './auth.middleware' 2 | import authStore from './auth.store' 3 | 4 | export default async function (ctx, inject) { 5 | const { store } = ctx 6 | 7 | // Inject $ctx 8 | inject('ctx', ctx) 9 | 10 | // Register auth store module 11 | store.registerModule('auth', authStore) 12 | 13 | // Fetch initial state 14 | try { 15 | await store.dispatch('auth/fetch') 16 | } catch (e) { 17 | // Not authorized 18 | // Check axios module is correctly registered 19 | if (!ctx.$axios) { 20 | /* eslint-disable no-console */ 21 | console.error('[@nuxtjs/auth]', 'Please make sure @nuxtjs/axios is added after this module!') 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pages/auth/login/index.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 32 | -------------------------------------------------------------------------------- /utils/vue-router/scrollBehavior.js: -------------------------------------------------------------------------------- 1 | module.exports = function(to, from, savedPosition) { 2 | // setTimeout(() => { 3 | let position = {}; 4 | if (savedPosition) { 5 | position = savedPosition; 6 | } else if (to.hash) { 7 | position = { selector: to.hash }; 8 | // setTimeout(() => { 9 | // document 10 | // .getElementById(to.hash.replace('#', '')) 11 | // .scrollIntoView({ behavior: 'smooth' }); 12 | // }, 700); 13 | } else if (to.matched.length < 2) { 14 | // scroll to the top of the page 15 | position = { x: 0, y: 0 }; 16 | } else if (to.matched.some(r => r.components.default.options.scrollToTop)) { 17 | // if one of the children has scrollToTop option set to true 18 | position = { x: 0, y: 0 }; 19 | } 20 | // global.console.log(position); 21 | return position; 22 | // }, 1000); 23 | }; 24 | -------------------------------------------------------------------------------- /api/auth.js: -------------------------------------------------------------------------------- 1 | export const checkExist = params => ({ 2 | method: 'get', 3 | url: 'auth/check/', 4 | params 5 | }); 6 | 7 | export const registration = data => ({ 8 | method: 'post', 9 | url: 'auth/registration/', 10 | data 11 | }); 12 | 13 | export const editUser = data => ({ 14 | method: 'put', 15 | url: 'auth/user/', 16 | data 17 | }); 18 | 19 | export const passwordChange = data => ({ 20 | method: 'post', 21 | url: 'auth/password/change/', 22 | data 23 | }); 24 | 25 | export const passwordReset = data => ({ 26 | method: 'post', 27 | url: 'auth/password/reset/', 28 | data 29 | }); 30 | 31 | export const passwordResetConfirm = data => ({ 32 | method: 'post', 33 | url: 'auth/password/reset/confirm/', 34 | data 35 | }); 36 | 37 | export const emailVerify = data => ({ 38 | method: 'post', 39 | url: '/auth/registration/verify-email/', 40 | data 41 | }); 42 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | env: { 5 | browser: true, 6 | node: true 7 | }, 8 | extends: ['airbnb-base', 'prettier'], 9 | // required to lint *.vue files 10 | plugins: ['html'], 11 | // add your custom rules here 12 | rules: { 13 | // allow paren-less arrow functions 14 | 'arrow-parens': 0, 15 | // allow debugger during development 16 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 17 | // do not allow console.logs etc... 18 | 'no-console': process.env.NODE_ENV === 'production' ? 2 : 0, 19 | // for root alias 20 | 'import/no-unresolved': [ 21 | 'error', 22 | { 23 | ignore: ['~/'] 24 | } 25 | ], 26 | 'no-param-reassign': 0, 27 | 'no-shadow': 0, 28 | 'import/no-extraneous-dependencies': 0, 29 | 'linebreak-style': 0 30 | }, 31 | globals: {} 32 | }; 33 | -------------------------------------------------------------------------------- /pages/auth/password/reset/index.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 36 | -------------------------------------------------------------------------------- /pages/auth/password/change/index.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 36 | -------------------------------------------------------------------------------- /pages/index.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plugins/veeValidate.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-extraneous-dependencies 2 | import Vue from 'vue'; 3 | import VeeValidate, { Validator } from 'vee-validate'; 4 | import ru from 'vee-validate/dist/locale/ru'; 5 | 6 | // Add locale helper. 7 | Validator.addLocale(ru); 8 | 9 | const config = { 10 | errorBagName: 'errors', // change if property conflicts. 11 | fieldsBagName: 'fields', 12 | delay: 0, 13 | locale: 'ru', 14 | dictionary: null, 15 | strict: true, 16 | classes: false, 17 | classNames: { 18 | touched: 'touched', // the control has been blurred 19 | untouched: 'untouched', // the control hasn't been blurred 20 | valid: 'valid', // model is valid 21 | invalid: 'invalid', // model is invalid 22 | pristine: 'pristine', // control has not been interacted with 23 | dirty: 'dirty' // control has been interacted with 24 | }, 25 | // events: 'input', 26 | events: 'input|blur', 27 | inject: true, 28 | validity: true, 29 | aria: true 30 | }; 31 | 32 | Vue.use(VeeValidate, config); 33 | -------------------------------------------------------------------------------- /pages/auth/registration/confirm-email/_key.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 39 | -------------------------------------------------------------------------------- /modules/@nuxtjs/auth/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Nuxt Community 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /modules/@nuxtjs/axios/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Nuxt Community 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pages/auth/password/reset/confirm/_uid/_token/index.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | -------------------------------------------------------------------------------- /store/auth.js: -------------------------------------------------------------------------------- 1 | import { auth as api } from '~/api'; // eslint-disable-line 2 | 3 | // main auth store in 'modules/nuxtjs/auth' 4 | 5 | export const getters = {}; 6 | 7 | export const actions = { 8 | async registration({ dispatch }, { fields, authAfter }) { 9 | const { data } = await this.$axios(api.registration(fields)); 10 | 11 | if (authAfter) { 12 | const token = data.token || data.id_token || data.key; // key in django default 13 | 14 | // Update new token 15 | await dispatch('updateToken', token); 16 | 17 | // Fetch authenticated user 18 | await dispatch('fetch'); 19 | } 20 | }, 21 | 22 | async editUser({ commit }, { fields } = {}) { 23 | const { data } = await this.$axios(api.editUser(fields)); 24 | commit('SET_USER', data); 25 | commit('users/SET_USER', data, { root: true }); 26 | }, 27 | 28 | async passwordChange(ctx, { fields }) { 29 | await this.$axios(api.passwordChange(fields)); 30 | }, 31 | 32 | async passwordReset(ctx, { fields }) { 33 | await this.$axios(api.passwordReset(fields)); 34 | }, 35 | 36 | async passwordResetConfirm(ctx, { fields }) { 37 | const { data } = await this.$axios(api.passwordResetConfirm(fields)); 38 | global.console.log(data); 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt.js_django-rest-framework", 3 | "version": "1.0.0", 4 | "description": "Nuxt.js project", 5 | "author": "RafiZz ", 6 | "private": true, 7 | "engines": { 8 | "node": "8.5.0", 9 | "npm": "5.4.2" 10 | }, 11 | "scripts": { 12 | "dev": "nuxt", 13 | "build": "nuxt build", 14 | "start": "nuxt start", 15 | "generate": "nuxt generate", 16 | "lint": "eslint --ext .js,.vue --ignore-path .gitignore .", 17 | "precommit": "npm run lint" 18 | }, 19 | "dependencies": { 20 | "axios": "0.16.2", 21 | "chalk": "2.1.0", 22 | "cookie": "0.3.1", 23 | "debug": "3.0.1", 24 | "js-cookie": "2.1.4", 25 | "nuxt": "1.0.0-rc8", 26 | "stylus": "0.54.5", 27 | "stylus-loader": "3.0.1", 28 | "vee-validate": "2.0.0-rc.16", 29 | "vuetify": "0.15.7", 30 | "whatwg-url": "6.1.0" 31 | }, 32 | "devDependencies": { 33 | "babel-eslint": "^7.2.3", 34 | "eslint": "^4.3.0", 35 | "eslint-config-airbnb-base": "^12.0.0", 36 | "eslint-config-prettier": "^2.4.0", 37 | "eslint-loader": "^1.9.0", 38 | "eslint-plugin-html": "^3.1.1", 39 | "eslint-plugin-import": "^2.7.0", 40 | "eslint-plugin-node": "^5.1.1", 41 | "eslint-plugin-promise": "^3.5.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /modules/@nuxtjs/auth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nuxtjs/auth", 3 | "version": "2.0.5", 4 | "description": "Authentication module for Nuxt.js", 5 | "license": "MIT", 6 | "contributors": [ 7 | { 8 | "name": "Pooya Parsa " 9 | } 10 | ], 11 | "main": "lib/index.js", 12 | "repository": "https://github.com/nuxt-community/auth-module", 13 | "publishConfig": { 14 | "access": "public" 15 | }, 16 | "scripts": { 17 | "build": "nuxt-module", 18 | "watch": "nuxt-module --watch", 19 | "lint": "eslint lib src test", 20 | "lint-fix": "eslint --fix lib src test", 21 | "test": "NODE_ENV=test npm run build && npm run lint && jest", 22 | "release": "standard-version && git push --follow-tags && npm publish", 23 | "prepare": "npm run build" 24 | }, 25 | "eslintIgnore": ["*.template.*"], 26 | "files": ["lib", "src", "lib", "templates"], 27 | "jest": { 28 | "testEnvironment": "node", 29 | "coverageDirectory": "./coverage/", 30 | "collectCoverage": true, 31 | "collectCoverageFrom": ["lib", "src"] 32 | }, 33 | "dependencies": { 34 | "@nuxtjs/axios": "^4.0.1", 35 | "cookie": "^0.3.1", 36 | "js-cookie": "^2.1.4" 37 | }, 38 | "devDependencies": { 39 | "nuxt-module-builder": "latest" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /store/users.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import { users as api } from '~/api'; // eslint-disable-line 3 | 4 | export const state = () => ({ 5 | count: 0, 6 | previous: null, 7 | next: null, 8 | results: {} 9 | }); 10 | 11 | export const mutations = { 12 | SET_USERS(state, { count, previous, next, results }) { 13 | state.count = count; 14 | state.previous = previous; 15 | state.next = next; 16 | if (results && results.length) { 17 | results.forEach(user => { 18 | Vue.set(state.results, user.id, user); 19 | }); 20 | } 21 | }, 22 | SET_USER(state, user) { 23 | Vue.set(state.results, user.id, user); 24 | } 25 | }; 26 | 27 | export const actions = { 28 | async fetchUsers({ commit }, { endpoint, params } = {}) { 29 | const { data } = await this.$axios(api.fetchUsers({ endpoint, params })); 30 | commit('SET_USERS', data); 31 | }, 32 | 33 | async fetchUser({ commit }, { id }) { 34 | const { data } = await this.$axios(api.fetchUser({ id })); 35 | commit('SET_USER', data); 36 | }, 37 | 38 | async getUserById({ dispatch, getters }, { id }) { 39 | const user = getters.byId(id) || (await dispatch('fetchUsers', { id })); 40 | return Promise.resolve(user); 41 | } 42 | }; 43 | 44 | export const getters = { 45 | toArray: state => () => Object.values(state.results), 46 | byId: state => id => state.results[id] 47 | }; 48 | -------------------------------------------------------------------------------- /components/auth/VerifyEmailDialog.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 50 | -------------------------------------------------------------------------------- /modules/@nuxtjs/auth/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | 6 | ## [2.0.5](https://github.com/nuxt-community/auth-module/compare/v2.0.4...v2.0.5) (2017-09-06) 7 | 8 | 9 | ### Bug Fixes 10 | 11 | * warn only needed ([a9dbe04](https://github.com/nuxt-community/auth-module/commit/a9dbe04)) 12 | 13 | 14 | 15 | 16 | ## [2.0.4](https://github.com/nuxt-community/auth-module/compare/v2.0.3...v2.0.4) (2017-09-05) 17 | 18 | 19 | ### Bug Fixes 20 | 21 | * warn when axios module is not registered ([6ace50b](https://github.com/nuxt-community/auth-module/commit/6ace50b)) 22 | 23 | 24 | 25 | 26 | ## [2.0.3](https://github.com/nuxt-community/auth-module/compare/v2.0.2...v2.0.3) (2017-09-04) 27 | 28 | 29 | ### Bug Fixes 30 | 31 | * **package:** publish templates ([eb1706a](https://github.com/nuxt-community/auth-module/commit/eb1706a)) 32 | 33 | 34 | 35 | 36 | ## [2.0.2](https://github.com/nuxt-community/auth-module/compare/v2.0.1...v2.0.2) (2017-09-04) 37 | 38 | 39 | 40 | 41 | ## [2.0.1](https://github.com/nuxt-community/auth-module/compare/v0.0.1...v2.0.1) (2017-09-04) 42 | 43 | 44 | 45 | 46 | ## 0.0.1 (2017-09-04) 47 | -------------------------------------------------------------------------------- /pages/auth/registration/index.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 50 | -------------------------------------------------------------------------------- /modules/@nuxtjs/auth/README.md: -------------------------------------------------------------------------------- 1 | # Auth 2 | 3 | [![npm (scoped with tag)](https://img.shields.io/npm/v/@nuxtjs/auth/latest.svg?style=flat-square)](https://npmjs.com/package/@nuxtjs/auth) 4 | [![npm](https://img.shields.io/npm/dt/@nuxtjs/auth.svg?style=flat-square)](https://npmjs.com/package/@nuxtjs/auth) 5 | [![CircleCI](https://img.shields.io/circleci/project/github/nuxt-community/auth-module.svg?style=flat-square)](https://circleci.com/gh/nuxt-community/auth-module) 6 | [![Codecov](https://img.shields.io/codecov/c/github/nuxt-community/auth-module.svg?style=flat-square)](https://codecov.io/gh/nuxt-community/auth-module) 7 | [![Dependencies](https://david-dm.org/nuxt-community/auth-module/status.svg?style=flat-square)](https://david-dm.org/nuxt-community/auth-module) 8 | 9 | [![js-standard-style](https://cdn.rawgit.com/standard/standard/master/badge.svg)](http://standardjs.com) 10 | 11 | > Authentication module for Nuxt.js 12 | 13 | [📖 **Release Notes**](./CHANGELOG.md) 14 | 15 | ## Setup 16 | - Add `@nuxtjs/auth` dependency using yarn or npm to your project 17 | - Add `@nuxtjs/auth` and `@nuxtjs/axios` to `modules` section of `nuxt.config.js` 18 | 19 | ```js 20 | { 21 | modules: [ 22 | '@nuxtjs/auth', 23 | 24 | // ...Axios module should be included AFTER @nuxtjs/auth 25 | '@nuxtjs/axios', 26 | ], 27 | auth: { 28 | /* auth options */ 29 | } 30 | } 31 | ``` 32 | 33 | ## Options 34 | 35 | 36 | 37 | ## License 38 | 39 | [MIT License](./LICENSE) 40 | 41 | Copyright (c) Nuxt Community -------------------------------------------------------------------------------- /modules/@nuxtjs/axios/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nuxtjs/axios", 3 | "version": "4.3.0", 4 | "description": "Secure and easy axios integration with Nuxt.js", 5 | "license": "MIT", 6 | "main": "lib/index.js", 7 | "repository": "https://github.com/nuxt-community/axios-module", 8 | "publishConfig": { 9 | "access": "public" 10 | }, 11 | "scripts": { 12 | "lint": "eslint lib src test", 13 | "test": "npm run lint && jest", 14 | "release": "standard-version && git push --follow-tags && npm publish", 15 | "prepare": "npm run test" 16 | }, 17 | "eslintIgnore": [ 18 | "*.template.*" 19 | ], 20 | "files": [ 21 | "lib", 22 | "src", 23 | "dist" 24 | ], 25 | "jest": { 26 | "testEnvironment": "node", 27 | "coverageDirectory": "./coverage/", 28 | "collectCoverage": true, 29 | "collectCoverageFrom": [ 30 | "lib", 31 | "test", 32 | "!test/fixture" 33 | ] 34 | }, 35 | "dependencies": { 36 | "axios": "^0.16.2", 37 | "chalk": "^2.1.0", 38 | "debug": "^3.0.1", 39 | "whatwg-url": "^6.1.0" 40 | }, 41 | "devDependencies": { 42 | "nuxt": "^1.0.0-rc8", 43 | "codecov": "^2.3.0", 44 | "eslint": "^4.5.0", 45 | "eslint-config-standard": "^10.2.1", 46 | "eslint-plugin-import": "^2.7.0", 47 | "eslint-plugin-jest": "^20.0.3", 48 | "eslint-plugin-node": "^5.1.1", 49 | "eslint-plugin-promise": "^3.5.0", 50 | "eslint-plugin-standard": "^3.0.1", 51 | "eslint-plugin-vue": "^2.1.0", 52 | "jest": "^20.0.4", 53 | "jsdom": "^11.1.0", 54 | "standard-version": "^4.2.0" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /components/auth/PasswordResetForm.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 53 | -------------------------------------------------------------------------------- /modules/@nuxtjs/auth/lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } 4 | 5 | var _require = require('path'); 6 | var resolve = _require.resolve; 7 | 8 | var index = (function () { 9 | var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(moduleOptions) { 10 | return regeneratorRuntime.wrap(function _callee$(_context) { 11 | while (1) { 12 | switch (_context.prev = _context.next) { 13 | case 0: 14 | // const options = Object.assign({}, this.options.auth, moduleOptions) 15 | 16 | // Plugin 17 | this.addPlugin({ src: resolve(__dirname, '../templates/auth.plugin.js'), fileName: 'auth.plugin.js' }); 18 | 19 | // Middleware 20 | this.addTemplate({ src: resolve(__dirname, '../templates/auth.middleware.js'), fileName: 'auth.middleware.js' }); 21 | 22 | // Store 23 | this.addTemplate({ src: resolve(__dirname, '../templates/auth.store.js'), fileName: 'auth.store.js' }); 24 | 25 | case 3: 26 | case 'end': 27 | return _context.stop(); 28 | } 29 | } 30 | }, _callee, this); 31 | })); 32 | 33 | function module(_x) { 34 | return _ref.apply(this, arguments); 35 | } 36 | 37 | return module; 38 | })(); 39 | 40 | module.exports = index; 41 | -------------------------------------------------------------------------------- /modules/@nuxtjs/axios/lib/index.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | const path = require('path') 3 | const { URL } = require('whatwg-url') 4 | const debug = require('debug')('nuxt:axios') 5 | 6 | module.exports = function nuxtAxios (moduleOptions) { 7 | const port = process.env.PORT || process.env.npm_package_config_nuxt_port || 3000 8 | let host = process.env.HOST || process.env.npm_package_config_nuxt_host || 'localhost' 9 | /* istanbul ignore if */ 10 | if (host === '0.0.0.0') { 11 | host = 'localhost' 12 | } 13 | 14 | // Apply defaults 15 | const defaults = { 16 | baseURL: `http://${host}:${port}/api`, 17 | browserBaseURL: null, 18 | credentials: true, 19 | proxyHeaders: true, 20 | debug: false, 21 | redirectError: {} 22 | } 23 | 24 | const options = Object.assign({}, defaults, this.options.axios, moduleOptions) 25 | 26 | // Override env 27 | /* istanbul ignore if */ 28 | if (process.env.API_URL) { 29 | options.baseURL = process.env.API_URL 30 | } 31 | 32 | /* istanbul ignore if */ 33 | if (process.env.API_URL_BROWSER) { 34 | options.browserBaseURL = process.env.API_URL_BROWSER 35 | } 36 | 37 | const isSchemeLessBaseURL = options.baseURL.substr(0, 2) === '//' 38 | options.baseURL = new URL(options.baseURL, `http://${host}:${port}`) 39 | 40 | if (!options.browserBaseURL) { 41 | const sameHost = options.baseURL.host === `${host}:${port}` 42 | options.browserBaseURL = sameHost ? options.baseURL.pathname : isSchemeLessBaseURL ? options.baseURL.toString().substr(5) : options.baseURL // 5 == 'http:'.length 43 | } 44 | 45 | // Register plugin 46 | this.addPlugin({ 47 | src: path.resolve(__dirname, 'plugin.template.js'), 48 | fileName: 'axios.js', 49 | options 50 | }) 51 | 52 | /* eslint-disable no-console */ 53 | debug(`BaseURL: ${chalk.green(options.baseURL)} (Browser: ${chalk.green(options.browserBaseURL)})`) 54 | } 55 | 56 | module.exports.meta = require('../package.json') 57 | -------------------------------------------------------------------------------- /store/settings.js: -------------------------------------------------------------------------------- 1 | import Cookie from 'cookie'; // eslint-disable-line import/no-extraneous-dependencies 2 | import Cookies from 'js-cookie'; // eslint-disable-line import/no-extraneous-dependencies 3 | 4 | export const state = () => ({ 5 | dark: false, 6 | firstDrawerClipped: false, 7 | firstDrawerRight: true, 8 | firstDrawerMini: false, 9 | secondDrawerRight: false, 10 | headerFixed: true, 11 | footerFixed: false, 12 | defaultAvatar: 'https://vk.com/images/camera_200.png' 13 | }); 14 | 15 | export const mutations = { 16 | SET_SETTINGS(state, settings) { 17 | if (settings && typeof settings === 'object') { 18 | Object.assign(state, settings); 19 | } 20 | }, 21 | CHANGE_SETTING(state, keys) { 22 | keys.split('|').forEach(key => { 23 | state[key] = !state[key]; 24 | }); 25 | } 26 | }; 27 | 28 | export const actions = { 29 | saveSettings({ state }) { 30 | if (process.browser && state) { 31 | const json = JSON.stringify(state); 32 | Cookies.set('settings', json); 33 | if (localStorage) { 34 | localStorage.setItem('nuxt::user::settings', json); 35 | } 36 | } 37 | }, 38 | loadSettings({ dispatch, commit }) { 39 | let userSettings; 40 | 41 | if (process.browser && localStorage) { 42 | userSettings = localStorage.getItem('nuxt::user::settings'); 43 | } 44 | 45 | if (process.browser && !userSettings) { 46 | const cookies = Cookie.parse(document.cookie || '') || {}; 47 | userSettings = cookies.settings; 48 | } 49 | 50 | if (!userSettings) return; 51 | 52 | try { 53 | userSettings = JSON.parse(userSettings); 54 | commit('SET_SETTINGS', userSettings); 55 | } catch (error) { 56 | global.console.log(`${error}`); 57 | dispatch('clearSettings'); 58 | } 59 | }, 60 | updateSettings({ commit, dispatch }, { ...settings }) { 61 | commit('SET_SETTINGS', settings); 62 | dispatch('saveSettings', settings); 63 | }, 64 | clearSettings() { 65 | if (process.browser) { 66 | Cookies.remove('settings'); 67 | if (localStorage) { 68 | localStorage.removeItem('nuxt::user::settings'); 69 | } 70 | global.console.log('Settings removed'); 71 | } 72 | } 73 | }; 74 | -------------------------------------------------------------------------------- /components/auth/LoginForm.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 65 | -------------------------------------------------------------------------------- /utils/mailProviders.js: -------------------------------------------------------------------------------- 1 | const mailProviders = [ 2 | // "почтовый домен", "название почтового сервиса","адрес для входа в почту" 3 | 'mail.ru', 4 | 'Почта Mail.Ru', 5 | 'https://e.mail.ru/', 6 | 'bk.ru', 7 | 'Почта Mail.Ru (bk.ru)', 8 | 'https://e.mail.ru/', 9 | 'list.ru', 10 | 'Почта Mail.Ru (list.ru)', 11 | 'https://e.mail.ru/', 12 | 'inbox.ru', 13 | 'Почта Mail.Ru (inbox.ru)', 14 | 'https://e.mail.ru/', 15 | 'yandex.ru', 16 | 'Яндекс.Почта', 17 | 'https://mail.yandex.ru/', 18 | 'ya.ru', 19 | 'Яндекс.Почта', 20 | 'https://mail.yandex.ru/', 21 | 'yandex.ua', 22 | 'Яндекс.Почта', 23 | 'https://mail.yandex.ua/', 24 | 'yandex.by', 25 | 'Яндекс.Почта', 26 | 'https://mail.yandex.by/', 27 | 'yandex.kz', 28 | 'Яндекс.Почта', 29 | 'https://mail.yandex.kz/', 30 | 'yandex.com', 31 | 'Yandex.Mail', 32 | 'https://mail.yandex.com/', 33 | 'gmail.com', 34 | 'Gmail', 35 | 'https://mail.google.com/', 36 | 'googlemail.com', 37 | 'Gmail', 38 | 'https://mail.google.com/', 39 | 'outlook.com', 40 | 'Outlook.com', 41 | 'https://mail.live.com/', 42 | 'hotmail.com', 43 | 'Outlook.com (Hotmail)', 44 | 'https://mail.live.com/', 45 | 'live.ru', 46 | 'Outlook.com (live.ru)', 47 | 'https://mail.live.com/', 48 | 'live.com', 49 | 'Outlook.com (live.com)', 50 | 'https://mail.live.com/', 51 | 'me.com', 52 | 'iCloud Mail', 53 | 'https://www.icloud.com/', 54 | 'icloud.com', 55 | 'iCloud Mail', 56 | 'https://www.icloud.com/', 57 | 'rambler.ru', 58 | 'Рамблер-Почта', 59 | 'https://mail.rambler.ru/', 60 | 'yahoo.com', 61 | 'Yahoo! Mail', 62 | 'https://mail.yahoo.com/', 63 | 'ukr.net', 64 | 'Почта ukr.net', 65 | 'https://mail.ukr.net/', 66 | 'i.ua', 67 | 'Почта I.UA', 68 | 'http://mail.i.ua/', 69 | 'bigmir.net', 70 | 'Почта Bigmir.net', 71 | 'http://mail.bigmir.net/', 72 | 'tut.by', 73 | 'Почта tut.by', 74 | 'https://mail.tut.by/', 75 | 'inbox.lv', 76 | 'Inbox.lv', 77 | 'https://www.inbox.lv/', 78 | 'mail.kz', 79 | 'Почта mail.kz', 80 | 'http://mail.kz/' 81 | ]; 82 | 83 | const mailProviderObjects = mailProviders.reduce((final, cur, index) => { 84 | if (index % 3 === 0) { 85 | final.push({}); 86 | final[final.length - 1].host = cur; 87 | } else if (index % 3 === 1) { 88 | final[final.length - 1].name = cur; 89 | } else { 90 | final[final.length - 1].href = cur; 91 | } 92 | return final; 93 | }, []); 94 | 95 | export default email => { 96 | const [, host] = email.split('@'); 97 | const provider = mailProviderObjects.find(prov => prov.host.includes(host)); 98 | return provider; 99 | }; 100 | -------------------------------------------------------------------------------- /components/auth/PasswordResetConfirmForm.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 84 | -------------------------------------------------------------------------------- /pages/settings/index.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 96 | -------------------------------------------------------------------------------- /components/auth/PasswordChangeForm.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 88 | -------------------------------------------------------------------------------- /modules/@nuxtjs/auth/templates/auth.store.js: -------------------------------------------------------------------------------- 1 | import Cookie from 'cookie'; 2 | import Cookies from 'js-cookie'; 3 | 4 | export default { 5 | namespaced: true, 6 | 7 | state: () => ({ 8 | token: null, 9 | user: null 10 | }), 11 | 12 | getters: { 13 | loggedIn: state => Boolean(state.user || state.token), 14 | user: state => state.user 15 | }, 16 | 17 | mutations: { 18 | // SET_USER 19 | SET_USER(state, user) { 20 | state.user = user; 21 | }, 22 | 23 | // SET_TOKEN 24 | SET_TOKEN(state, token) { 25 | state.token = token; 26 | } 27 | }, 28 | 29 | actions: { 30 | updateToken({ commit }, token) { 31 | // Update state 32 | commit('SET_TOKEN', token); 33 | 34 | // Update localStorage 35 | if (process.browser && localStorage) { 36 | if (token) { 37 | localStorage.setItem('nuxt::auth::token', token); 38 | } else { 39 | localStorage.removeItem('nuxt::auth::token'); 40 | } 41 | } 42 | 43 | // Update cookies 44 | if (process.browser) { 45 | // ...Browser 46 | if (token) { 47 | Cookies.set('token', token); 48 | } else { 49 | Cookies.remove('token'); 50 | } 51 | } else { 52 | // ...Server 53 | // TODO: Use set-cookie header for this.$ctx.res 54 | } 55 | }, 56 | 57 | fetchToken({ dispatch }) { 58 | let token; 59 | 60 | // First try localStorage 61 | if (process.browser && localStorage) { 62 | token = localStorage.getItem('nuxt::auth::token'); 63 | } 64 | 65 | // Then try to extract token from cookies 66 | if (!token) { 67 | const cookieStr = process.browser 68 | ? document.cookie 69 | : this.$ctx.req.headers.cookie; 70 | const cookies = Cookie.parse(cookieStr || '') || {}; 71 | token = cookies.token; 72 | } 73 | 74 | if (token) { 75 | dispatch('updateToken', token); 76 | } 77 | }, 78 | 79 | async invalidate({ dispatch, commit }) { 80 | commit('SET_USER', null); 81 | await dispatch('updateToken', null); 82 | }, 83 | 84 | async fetch({ state, commit, dispatch }, { endpoint = 'auth/user/' } = {}) { 85 | // Fetch and update latest token 86 | await dispatch('fetchToken'); 87 | 88 | // Not loggedIn 89 | if (!state.token) { 90 | return; 91 | } 92 | 93 | // Try to get user profile 94 | try { 95 | const userData = await this.$axios.$get(endpoint); 96 | commit('SET_USER', userData); 97 | } catch (e) { 98 | return dispatch('invalidate'); 99 | } 100 | }, 101 | 102 | // Login 103 | async login( 104 | { commit, dispatch }, 105 | { fields, endpoint = 'auth/login/', session = false } = {} 106 | ) { 107 | // Send credentials to API 108 | const tokenData = await this.$axios.$post(endpoint, fields); 109 | const token = tokenData.token || tokenData.id_token || tokenData.key; 110 | 111 | // Update new token 112 | await dispatch('updateToken', token); 113 | 114 | // Fetch authenticated user 115 | await dispatch('fetch'); 116 | }, 117 | 118 | // Logout 119 | async logout( 120 | { commit, dispatch, state }, 121 | { endpoint = 'auth/logout/', appendToken = false } = {} 122 | ) { 123 | // Append token 124 | if (appendToken) { 125 | endpoint += state.token; 126 | } 127 | 128 | // Server side logout 129 | try { 130 | await this.$axios.$get(endpoint); 131 | } catch (e) { 132 | // eslint-disable-next-line no-console 133 | console.error('Error while logging out', e); 134 | } 135 | 136 | // Unload user profile & token 137 | await dispatch('invalidate'); 138 | } 139 | } 140 | }; 141 | -------------------------------------------------------------------------------- /nuxt.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | /* 3 | ** Headers of the page 4 | */ 5 | head: { 6 | title: 'Nuxt.js + Django REST Framework', 7 | // bodyAttrs: { 8 | // id: 'body' 9 | // }, 10 | meta: [ 11 | { charset: 'utf-8' }, 12 | { 13 | name: 'viewport', 14 | content: 15 | 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no' 16 | }, 17 | { 18 | hid: 'description', 19 | name: 'description', 20 | content: 'Nuxt.js + Django REST Framework' 21 | }, 22 | { name: 'apple-mobile-web-app-capable', content: 'yes' }, 23 | { name: 'apple-touch-fullscreen', content: 'yes' }, 24 | { name: 'apple-mobile-web-app-status-bar-style', content: 'default' } 25 | ], 26 | link: [ 27 | { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, 28 | { 29 | rel: 'stylesheet', 30 | href: 31 | 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' 32 | } 33 | ] 34 | }, 35 | css: ['~/assets/style/app.styl'], 36 | /* 37 | ** Customize the progress-bar color 38 | */ 39 | loading: { color: '#3B8070' }, 40 | /* 41 | ** Build configuration 42 | */ 43 | build: { 44 | /* 45 | ** Run ESLINT on save 46 | */ 47 | extend(config, ctx) { 48 | config.node = { fs: 'empty' }; 49 | if (ctx.dev && ctx.isClient) { 50 | config.module.rules.push({ 51 | enforce: 'pre', 52 | test: /\.(js|vue)$/, 53 | loader: 'eslint-loader', 54 | exclude: /(node_modules)/ 55 | }); 56 | } 57 | }, 58 | vendor: ['vee-validate', 'vuetify'], 59 | extractCSS: true 60 | }, 61 | plugins: ['~/plugins/veeValidate', '~/plugins/vuetify.js'], 62 | modules: [ 63 | // '@nuxtjs/auth', 64 | [ 65 | '~/modules/@nuxtjs/auth', 66 | { 67 | /* auth options */ 68 | } 69 | ], 70 | // ...Axios module should be included AFTER @nuxtjs/auth 71 | // '@nuxtjs/axios' 72 | [ 73 | '~/modules/@nuxtjs/axios', 74 | { 75 | credentials: false, 76 | // redirectError: '/auth/login', 77 | redirectError: { 78 | 401: '/auth/login', 79 | 403: '/auth/login' 80 | }, 81 | requestInterceptor: (config, { store }) => { 82 | if (store.state.auth.token) { 83 | config.headers.common.authorization = `Token ${store.state.auth 84 | .token}`; 85 | } 86 | return config; 87 | }, 88 | responseInterceptor: (response, ctx) => { 89 | // global.console.log(ctx); 90 | return response; 91 | } 92 | } 93 | ] 94 | ], 95 | env: { 96 | API_URL: process.env.API_URL || 'http://localhost:8000/api/v1', 97 | API_URL_BROWSER: 98 | process.env.API_URL_BROWSER || 'http://localhost:8000/api/v1', 99 | WS_URL: process.env.WS_URL || 'localhost:8000' 100 | }, 101 | /* 102 | ** Router configuration 103 | */ 104 | router: { 105 | // base: '/', 106 | mode: 'history', 107 | linkActiveClass: 'nuxt-link-active', 108 | linkExactActiveClass: 'nuxt-link-exact-active', 109 | scrollBehavior: require('./utils/vue-router/scrollBehavior'), 110 | // Run the middleware/user-agent.js on every pages 111 | middleware: ['user-agent'] 112 | // extendRoutes(routes, resolve) { 113 | // routes.push({ 114 | // name: 'custom', 115 | // path: '*', 116 | // component: resolve(__dirname, 'pages/wizard.vue') 117 | // }); 118 | // } 119 | }, 120 | transition: { 121 | name: 'page', 122 | mode: 'out-in', 123 | beforeEnter: require('./utils/transition/beforeEnter') 124 | }, 125 | // transition (to, from) { 126 | // if (!from) return 'slide-left' 127 | // return +to.query.page < +from.query.page ? 'slide-right' : 'slide-left' 128 | // } 129 | render: { 130 | bundleRenderer: { 131 | cache: require('lru-cache')({ 132 | max: 1000, 133 | maxAge: 1000 * 60 * 15 134 | }) 135 | } 136 | } 137 | }; 138 | -------------------------------------------------------------------------------- /components/auth/RegistrationForm.vue: -------------------------------------------------------------------------------- 1 | 50 | 51 | 105 | -------------------------------------------------------------------------------- /pages/users/_id.vue: -------------------------------------------------------------------------------- 1 | 90 | 91 | 109 | -------------------------------------------------------------------------------- /pages/users/index.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | 127 | -------------------------------------------------------------------------------- /layouts/baseLayout.vue: -------------------------------------------------------------------------------- 1 | 114 | 115 | -------------------------------------------------------------------------------- /components/auth/UserEditForm.vue: -------------------------------------------------------------------------------- 1 | 104 | 105 | 177 | -------------------------------------------------------------------------------- /modules/@nuxtjs/axios/lib/plugin.template.js: -------------------------------------------------------------------------------- 1 | import Axios from 'axios' 2 | import Vue from 'vue' 3 | 4 | // We cannot extend Axios.prototype 5 | const axiosExtraProto = {} 6 | 7 | // Sets a common header 8 | axiosExtraProto.setHeader = function setHeader (name, value, scopes = 'common') { 9 | if(!Array.isArray(scopes)) { 10 | scopes = [scopes] 11 | } 12 | scopes.forEach(scope => { 13 | if (!value) { 14 | delete this.defaults.headers[scope][name]; 15 | return 16 | } 17 | this.defaults.headers[scope][name] = value 18 | }) 19 | } 20 | 21 | // Set requests token 22 | axiosExtraProto.setToken = function setToken (token, type, scopes = 'common') { 23 | const value = !token ? null : (type ? type + ' ' : '') + token 24 | this.setHeader('Authorization', value, scopes) 25 | } 26 | 27 | // Request helpers 28 | const reqMethods = [ 29 | 'request', 'delete', 'get', 'head', 'options', // url, config 30 | 'post', 'put', 'patch' // url, data, config 31 | ] 32 | reqMethods.forEach(method => { 33 | axiosExtraProto['$' + method] = function () { 34 | return this[method].apply(this, arguments).then(res => res && res.data) 35 | } 36 | }) 37 | 38 | // Setup all helpers to axios instance (Axios.prototype cannot be modified) 39 | function setupHelpers( axios ) { 40 | for (let key in axiosExtraProto) { 41 | axios[key] = axiosExtraProto[key].bind(axios) 42 | } 43 | } 44 | 45 | const redirectError = <%= serialize(options.redirectError) %> 46 | 47 | // Set appreciate `statusCode` and `message` to error instance 48 | function errorHandler(error, ctx) { 49 | if (error.response) { 50 | // Error from backend (non 2xx status code) 51 | // ...Auto redirect on special status codes 52 | if (redirectError[error.response.status]) { 53 | ctx.redirect(redirectError[error.response.status]) 54 | } 55 | error.statusCode = error.statusCode || parseInt(error.response.status) || 500 56 | error.message = error.message || error.response.statusText || (error.statusCode + ' (Internal Server Error)') 57 | } else if (error.request) { 58 | // Error while making request 59 | error.statusCode = error.statusCode || 500 60 | error.message = error.message || 'request error' 61 | } else { 62 | // Something happened in setting up the request that triggered an Error 63 | error.statusCode = error.statusCode || 0 64 | error.message = error.message || 'axios error' 65 | } 66 | 67 | return Promise.reject(error) 68 | } 69 | 70 | <% if (options.errorHandler) { %> 71 | const customErrorHandler = <%= serialize(options.errorHandler).replace('errorHandler(', 'function(').replace('function function', 'function') %> 72 | <% } %> 73 | 74 | <% if(options.debug) { %> 75 | function debug(level, messages) { 76 | if (!(console[level] instanceof Function)) { 77 | level = 'info' 78 | messages = arguments 79 | } else { 80 | level = arguments[0] 81 | messages = Array.prototype.slice.call(arguments, 1) 82 | } 83 | 84 | if (!messages.length) { 85 | console[level].call(null, '[@nuxtjs/axios] ') 86 | } else { 87 | for (var i = 0; i < messages.length; i++) { 88 | console[level].call(null, messages[i]) 89 | } 90 | } 91 | } 92 | <% } %> 93 | 94 | // Setup BaseURL 95 | const baseURL = process.browser 96 | ? (process.env.API_URL_BROWSER || '<%= options.browserBaseURL %>') 97 | : (process.env.API_URL || '<%= options.baseURL %>') 98 | 99 | // Custom init hook 100 | <% if (options.init) { %> 101 | const initHook = <%= serialize(options.init).replace('init(', 'function(').replace('function function', 'function') %> 102 | <% } %> 103 | 104 | export default <% if (options.init) { %>async<% } %>(ctx, inject) => { 105 | const { app, store, req } = ctx 106 | 107 | // Create a fresh objects for all default header scopes 108 | // Axios creates only one which is shared across SSR requests! 109 | // https://github.com/mzabriskie/axios/blob/master/lib/defaults.js 110 | const headers = { 111 | common : { 112 | 'Accept': 'application/json, text/plain, */*' 113 | }, 114 | delete: {}, 115 | get: {}, 116 | head: {}, 117 | post: {}, 118 | put: {}, 119 | patch: {} 120 | } 121 | 122 | <% if(options.proxyHeaders) { %> 123 | // Default headers 124 | headers.common = (req && req.headers) ? Object.assign({}, req.headers) : {} 125 | delete headers.common.host 126 | delete headers.common.accept 127 | <% } %> 128 | 129 | // Create new axios instance 130 | const axios = Axios.create({ 131 | baseURL, 132 | headers 133 | }) 134 | 135 | <% if (options.credentials) { %> 136 | // Send credentials only to relative and API Backend requests 137 | axios.interceptors.request.use(config => { 138 | if (config.withCredentials === undefined) { 139 | if (!/^https?:\/\//i.test(config.url) || config.url.indexOf(baseURL) === 0) { 140 | config.withCredentials = true 141 | } 142 | } 143 | return config 144 | }); 145 | <% } %> 146 | 147 | <% if(options.debug) { %> 148 | // Debug 149 | axios.interceptors.request.use(config => { 150 | debug('[@nuxtjs/axios] Request:', config) 151 | return config 152 | }, error => { 153 | debug('error', '[@nuxtjs/axios] Error:', error) 154 | return Promise.reject(error) 155 | }); 156 | axios.interceptors.response.use(config => { 157 | debug('[@nuxtjs/axios] Response:', config) 158 | return config 159 | }, error => { 160 | debug('error', '[@nuxtjs/axios] Error:', error) 161 | return Promise.reject(error) 162 | }); 163 | <% } %> 164 | 165 | <% if (options.requestInterceptor) { %> 166 | // Custom request interceptor 167 | const reqInter = <%= serialize(options.requestInterceptor).replace('requestInterceptor(', 'function(').replace('function function', 'function') %> 168 | axios.interceptors.request.use(config => reqInter(config, ctx)) 169 | <% } %> 170 | 171 | <% if (options.responseInterceptor) { %> 172 | // Custom response interceptor 173 | const resInter = <%= serialize(options.responseInterceptor).replace('responseInterceptor(', 'function(').replace('function function', 'function') %> 174 | axios.interceptors.response.use(config => resInter(config, ctx)) 175 | <% } %> 176 | 177 | // Error handler 178 | axios.interceptors.response.use(undefined, err => errorHandler(err, ctx)); 179 | 180 | <% if (options.errorHandler) { %> 181 | // Custom error handler 182 | axios.interceptors.response.use(undefined, err => customErrorHandler(err, ctx)) 183 | <% } %> 184 | 185 | // Inject axios to the context as $axios 186 | ctx.$axios = axios 187 | inject('axios', axios) 188 | 189 | <% if (options.init) { %> 190 | await initHook(axios, ctx) 191 | <% } %> 192 | 193 | 194 | // Setup axios helpers 195 | setupHelpers(axios) 196 | } 197 | -------------------------------------------------------------------------------- /modules/@nuxtjs/axios/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | 6 | # [4.3.0](https://github.com/nuxt-community/axios-module/compare/v4.2.1...v4.3.0) (2017-09-11) 7 | 8 | 9 | ### Features 10 | 11 | * don't rely on hostname for default values ([dadd7d8](https://github.com/nuxt-community/axios-module/commit/dadd7d8)) 12 | 13 | 14 | 15 | 16 | ## [4.2.1](https://github.com/nuxt-community/axios-module/compare/v4.2.0...v4.2.1) (2017-09-08) 17 | 18 | 19 | 20 | 21 | # [4.2.0](https://github.com/nuxt-community/axios-module/compare/v4.1.1...v4.2.0) (2017-09-08) 22 | 23 | 24 | ### Features 25 | 26 | * pass ctx to errorHandlers ([c70749a](https://github.com/nuxt-community/axios-module/commit/c70749a)) 27 | 28 | 29 | 30 | 31 | ## [4.1.1](https://github.com/nuxt-community/axios-module/compare/v4.1.0...v4.1.1) (2017-09-06) 32 | 33 | 34 | ### Bug Fixes 35 | 36 | * delete accept header ([2f04e30](https://github.com/nuxt-community/axios-module/commit/2f04e30)), closes [#12](https://github.com/nuxt-community/axios-module/issues/12) 37 | 38 | 39 | 40 | 41 | # [4.1.0](https://github.com/nuxt-community/axios-module/compare/v4.0.1...v4.1.0) (2017-09-06) 42 | 43 | 44 | ### Bug Fixes 45 | 46 | * inject $axios in current ctx ([356b31f](https://github.com/nuxt-community/axios-module/commit/356b31f)) 47 | 48 | 49 | ### Features 50 | 51 | * add options.init ([8e0c0e8](https://github.com/nuxt-community/axios-module/commit/8e0c0e8)) 52 | 53 | 54 | ### Performance Improvements 55 | 56 | * move init outside of plugin ([bcd4710](https://github.com/nuxt-community/axios-module/commit/bcd4710)) 57 | 58 | 59 | 60 | 61 | ## [4.0.1](https://github.com/nuxt-community/axios-module/compare/v4.0.0...v4.0.1) (2017-09-04) 62 | 63 | 64 | ### Bug Fixes 65 | 66 | * **package:** make nuxt devDependency ([a36a886](https://github.com/nuxt-community/axios-module/commit/a36a886)) 67 | 68 | 69 | 70 | 71 | # [4.0.0](https://github.com/nuxt-community/axios-module/compare/v3.1.4...v4.0.0) (2017-08-30) 72 | 73 | 74 | ### Features 75 | 76 | * better baseURL message ([61432a1](https://github.com/nuxt-community/axios-module/commit/61432a1)) 77 | * responseInterceptor and errorHandler ([b16d6bf](https://github.com/nuxt-community/axios-module/commit/b16d6bf)) 78 | * upgrade for nuxt rc8 ([a341185](https://github.com/nuxt-community/axios-module/commit/a341185)) 79 | 80 | 81 | ### BREAKING CHANGES 82 | 83 | * app.axios is not available anymore (without $) should always use app.$axios 84 | 85 | 86 | 87 | 88 | ## [3.1.4](https://github.com/nuxt-community/axios-module/compare/v3.1.3...v3.1.4) (2017-08-13) 89 | 90 | 91 | ### Bug Fixes 92 | 93 | * create fresh objects for all default header scopes ([7ba3ae8](https://github.com/nuxt-community/axios-module/commit/7ba3ae8)) 94 | 95 | 96 | 97 | 98 | ## [3.1.3](https://github.com/nuxt-community/axios-module/compare/v3.1.1...v3.1.3) (2017-08-13) 99 | 100 | ### Bug Fixes 101 | 102 | * **headers:** fix security bug with default request headers ([9355228](https://github.com/nuxt-community/axios-module/commit/9355228)) 103 | 104 | 105 | 106 | 107 | ## 3.1.1 (2017-08-13) 108 | (repository moved from nuxt-community/modules) 109 | 110 | ### Features 111 | 112 | * **axios:** fetch style requests 113 | 114 | 115 | ## [3.0.1](https://github.com/nuxt/modules/compare/@nuxtjs/axios@3.0.0...@nuxtjs/axios@3.0.1) (2017-07-25) 116 | 117 | 118 | ### Bug Fixes 119 | 120 | * **axios:** typo in default headers ([9697559](https://github.com/nuxt/modules/commit/9697559)) 121 | 122 | 123 | 124 | 125 | 126 | # [3.0.0](https://github.com/nuxt/modules/compare/@nuxtjs/axios@2.3.0...@nuxtjs/axios@3.0.0) (2017-07-25) 127 | 128 | 129 | ### Code Refactoring 130 | 131 | * **axios:** remove $ shortcut mixins ([1ab2bd6](https://github.com/nuxt/modules/commit/1ab2bd6)) 132 | 133 | 134 | ### BREAKING CHANGES 135 | 136 | * **axios:** You have to explicitly use `this.$axios.[method]` instead of `this.$[method]` 137 | 138 | 139 | 140 | 141 | 142 | # [2.3.0](https://github.com/nuxt/modules/compare/@nuxtjs/axios@2.2.4...@nuxtjs/axios@2.3.0) (2017-07-24) 143 | 144 | 145 | ### Features 146 | 147 | * **axios:** optionally disable error handling (#74) ([a195feb](https://github.com/nuxt/modules/commit/a195feb)) 148 | * **axios:** redirectError ([4ce1a1c](https://github.com/nuxt/modules/commit/4ce1a1c)) 149 | 150 | 151 | 152 | 153 | 154 | ## [2.2.4](https://github.com/nuxt/modules/compare/@nuxtjs/axios@2.2.3...@nuxtjs/axios@2.2.4) (2017-07-20) 155 | 156 | 157 | ### Bug Fixes 158 | 159 | * **axios:** temporary fix for nuxt/nuxt.js#1127 ([499b639](https://github.com/nuxt/modules/commit/499b639)), closes [nuxt/nuxt.js#1127](https://github.com/nuxt/nuxt.js/issues/1127) 160 | 161 | 162 | 163 | 164 | 165 | ## [2.2.3](https://github.com/nuxt/modules/compare/@nuxtjs/axios@2.2.1...@nuxtjs/axios@2.2.3) (2017-07-19) 166 | 167 | 168 | ### Bug Fixes 169 | 170 | * **axios:** don't proxy Host header from request (#72, #39) ([61462ca](https://github.com/nuxt/modules/commit/61462ca)) 171 | 172 | 173 | 174 | 175 | 176 | ## [2.2.2](https://github.com/nuxt/modules/compare/@nuxtjs/axios@2.2.1...@nuxtjs/axios@2.2.2) (2017-07-19) 177 | 178 | 179 | ### Bug Fixes 180 | 181 | * **axios:** don't proxy Host header from request (#72, #39) ([61462ca](https://github.com/nuxt/modules/commit/61462ca)) 182 | 183 | 184 | 185 | 186 | 187 | ## [2.2.1](https://github.com/nuxt/modules/compare/@nuxtjs/axios@2.2.0...@nuxtjs/axios@2.2.1) (2017-07-15) 188 | 189 | 190 | ### Bug Fixes 191 | 192 | * **axios:** problems related to #65 ([4e7dd3f](https://github.com/nuxt/modules/commit/4e7dd3f)) 193 | 194 | 195 | 196 | 197 | 198 | ## [2.0.3](https://github.com/nuxt/modules/compare/@nuxtjs/axios@2.0.2...@nuxtjs/axios@2.0.3) (2017-06-10) 199 | 200 | 201 | ### Bug Fixes 202 | 203 | * **axios:** Handle relative baseURL ([19b8453](https://github.com/nuxt/modules/commit/19b8453)) 204 | * handle 0.0.0.0 host ([610e0f5](https://github.com/nuxt/modules/commit/610e0f5)) 205 | 206 | 207 | 208 | 209 | 210 | ## [2.0.2](https://github.com/nuxt/modules/compare/@nuxtjs/axios@2.0.1...@nuxtjs/axios@2.0.2) (2017-06-09) 211 | 212 | 213 | ### Bug Fixes 214 | 215 | * **axios:** Node 6.x support ([54deac0](https://github.com/nuxt/modules/commit/54deac0)) 216 | 217 | 218 | 219 | 220 | 221 | ## [2.0.1](https://github.com/nuxt/modules/compare/@nuxtjs/axios@2.0.0...@nuxtjs/axios@2.0.1) (2017-06-09) 222 | 223 | 224 | ### Bug Fixes 225 | 226 | * **axios:** ensure store exists before injecting ([23ad7b7](https://github.com/nuxt/modules/commit/23ad7b7)) 227 | 228 | 229 | 230 | 231 | 232 | # [2.0.0](https://github.com/nuxt/modules/compare/@nuxtjs/axios@1.0.2...@nuxtjs/axios@2.0.0) (2017-06-09) 233 | 234 | 235 | ### Bug Fixes 236 | 237 | * **axios:** install using Vue.use ([184651b](https://github.com/nuxt/modules/commit/184651b)) 238 | * **axios:** req typo ([16f28b1](https://github.com/nuxt/modules/commit/16f28b1)) 239 | * **axios:** use relative `API_URL` if same host and port else `API_URL` ([3421d19](https://github.com/nuxt/modules/commit/3421d19)) 240 | 241 | 242 | ### Features 243 | 244 | * **axios:** AXIOS_CREDENTIALS, AXIOS_SSR_HEADERS ([4dfdc2d](https://github.com/nuxt/modules/commit/4dfdc2d)) 245 | * **axios:** don't append optional config into env ([fe189e8](https://github.com/nuxt/modules/commit/fe189e8)) 246 | * **axios:** Easier API ([f54a434](https://github.com/nuxt/modules/commit/f54a434)) 247 | * **axios:** New API ([0194226](https://github.com/nuxt/modules/commit/0194226)) 248 | * **axios:** nuxt friendly errors for SSR ([65bc50f](https://github.com/nuxt/modules/commit/65bc50f)) 249 | 250 | 251 | ### BREAKING CHANGES 252 | 253 | * **axios:** API_PREFIX is deprecated. 254 | 255 | 256 | 257 | 258 | 259 | ## [1.0.2](https://github.com/nuxt/modules/compare/@nuxtjs/axios@1.0.0...@nuxtjs/axios@1.0.2) (2017-05-29) 260 | 261 | 262 | ### Bug Fixes 263 | 264 | * **axios:** remove extra function call on computed prop ([cd9da0b](https://github.com/nuxt/modules/commit/cd9da0b)) 265 | 266 | 267 | 268 | 269 | 270 | ## [1.0.1](https://github.com/nuxt/modules/compare/@nuxtjs/axios@1.0.0...@nuxtjs/axios@1.0.1) (2017-05-26) 271 | 272 | 273 | ### Bug Fixes 274 | 275 | * **axios:** remove extra function call on computed prop ([cd9da0b](https://github.com/nuxt/modules/commit/cd9da0b)) 276 | 277 | 278 | 279 | 280 | 281 | # 1.0.0 (2017-05-26) 282 | 283 | 284 | ### Features 285 | 286 | * initial migration to 1.0.0-alpha1 ([05c1b7a](https://github.com/nuxt/modules/commit/05c1b7a)) 287 | 288 | 289 | ### BREAKING CHANGES 290 | 291 | * New modules system is backward incompatible with nuxt-helpers style modules 292 | 293 | 294 | 295 | 296 | 297 | ## 0.0.1 (2017-05-10) 298 | -------------------------------------------------------------------------------- /modules/@nuxtjs/axios/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |

26 | 27 |

Axios

28 | 29 |

Secure and Easy Axios integration with Nuxt.js.

30 | 31 | [📖 Release Notes](./CHANGELOG.md) 32 | 33 | # Table of Contents 34 | 35 | - [Features](#features) 36 | - [Setup](#setup) 37 | - [Usage](#usage) 38 | - [Component](#component-asyncdata) 39 | - [Store](#store-nuxtserverinit) 40 | - [Store Actions](#store-actions) 41 | - [Options](#options) 42 | - [browserBaseURL](#browserbaseurl) 43 | - [credentials](#credentials) 44 | - [debug](#debug) 45 | - [proxyHeaders](#proxyheaders) 46 | - [redirectError](#redirecterror) 47 | - [requestInterceptor](#requestinterceptor) 48 | - [responseInterceptor](#responseinterceptor) 49 | - [init](#init) 50 | - [errorHandler](#errorhandler) 51 | - [Helpers](#helpers) 52 | - [Fetch Style Requests](#fetch-style-requests) 53 | - [Set Header](#setheadername-value-scopescommon) 54 | - [Set Token](#settokentoken-type-scopescommon) 55 | - [Dynamic API Backend](#dynamic-api-backend) 56 | 57 | ## Features 58 | 59 | - Automatically set base URL for client & server side 60 | - Exposes `setToken` function to `$axios` so we can easily and globally set authentication tokens 61 | - Throws *nuxt-friendly* errors and optionally redirect on specific error codes 62 | - Automatically enables `withCredentials` when requesting to base URL](#credentials) 63 | - Proxy request headers in SSR (Useful for auth) 64 | - Fetch Style requests 65 | 66 | ## Setup 67 | 68 | Install with npm: 69 | ```bash 70 | >_ npm install @nuxtjs/axios 71 | ``` 72 | 73 | Install with yarn: 74 | ```bash 75 | >_ yarn add @nuxtjs/axios 76 | ``` 77 | 78 | **nuxt.config.js** 79 | 80 | ```js 81 | { 82 | modules: [ 83 | '@nuxtjs/axios', 84 | ], 85 | 86 | axios: { 87 | // proxyHeaders: false 88 | } 89 | } 90 | ``` 91 | 92 | ## Usage 93 | 94 | ### Component `asyncData` 95 | 96 | ```js 97 | async asyncData({ app }) { 98 | const ip = await app.$axios.$get('http://icanhazip.com') 99 | return { ip } 100 | } 101 | ``` 102 | 103 | ### Store `nuxtServerInit` 104 | ```js 105 | async nuxtServerInit ({ commit }, { app }) { 106 | const ip = await app.$axios.$get('http://icanhazip.com') 107 | commit('SET_IP', ip) 108 | } 109 | ``` 110 | 111 | ### Store actions 112 | (Needs Nuxt >= 1.0.0-RC8) 113 | 114 | ```js 115 | // In store 116 | { 117 | actions: { 118 | async getIP ({ commit }) { 119 | const ip = await this.$axios.$get('http://icanhazip.com') 120 | commit('SET_IP', ip) 121 | } 122 | } 123 | } 124 | ``` 125 | 126 | ## Options 127 | You can pass options using module options or `axios` section in `nuxt.config.js` 128 | 129 | ### `baseURL` 130 | - Default: `http://[HOST]:[PORT]/api` 131 | 132 | Base URL is required for requests in server-side & SSR and prepended to all requests with relative path. 133 | You can also use environment variable `API_URL` which **overrides** `baseURL`. 134 | 135 | ### `browserBaseURL` 136 | - Default: `/api` 137 | 138 | Base URL which is used in client side prepended to all requests with relative path. 139 | You can also use environment variable `API_URL_BROWSER` which **overrides** `browserBaseURL`. 140 | 141 | - If `browserBaseURL` is not provided it defaults to `baseURL` value. 142 | - If hostname & port of `browserbaseURL` are equal to nuxt server, it defaults to relative part of `baseURL`. 143 | So if your nuxt application is being accessed under a different domain, requests go to same origin and prevents Cross-Origin problems. 144 | 145 | ### `credentials` 146 | - Default: `true` 147 | 148 | Adds an interceptor to automatically set `withCredentials` config of axios when requesting to `baseUrl` 149 | which allows passing authentication headers to backend. 150 | 151 | ### `debug` 152 | - Default: `false` 153 | 154 | Adds interceptors to log all responses and requests 155 | 156 | ### `proxyHeaders` 157 | - Default: `true` 158 | 159 | In SSR context, sets client request header as axios default request headers. 160 | This is useful for making requests which need cookie based auth on server side. 161 | Also helps making consistent requests in both SSR and Client Side code. 162 | 163 | > **NOTE:** If directing requests at a url protected by CloudFlare's CDN you should set this to false to prevent CloudFlare from mistakenly detecting a reverse proxy loop and returning a 403 error. 164 | 165 | ### `redirectError` 166 | - Default: `{}` 167 | 168 | This option is a map from specific error codes to page which they should be redirect. 169 | For example if you want redirecting all `401` errors to `/login` use: 170 | ```js 171 | axios: { 172 | redirectError: { 173 | 401: '/login' 174 | } 175 | } 176 | ``` 177 | 178 | ### `requestInterceptor` 179 | - Default: `null` 180 | 181 | Function for manipulating axios requests. Useful for setting custom headers, 182 | for example based on the store state. The second argument is the nuxt context. 183 | 184 | ```js 185 | requestInterceptor: (config, { store }) => { 186 | if (store.state.token) { 187 | config.headers.common['Authorization'] = store.state.token 188 | } 189 | return config 190 | } 191 | ``` 192 | 193 | ### `responseInterceptor` 194 | - Default: `null` 195 | 196 | ```js 197 | responseInterceptor: (response, ctx) => { 198 | return response 199 | } 200 | ``` 201 | 202 | 203 | Function for manipulating axios responses. 204 | 205 | ### `init` 206 | - Default: `null` 207 | 208 | Function `init(axios, ctx)` to do additional things with axios. Example: 209 | 210 | ```js 211 | axios: { 212 | init(axios, ctx) { 213 | axios.defaults.xsrfHeaderName = 'X-CSRF-TOKEN' 214 | } 215 | } 216 | ``` 217 | 218 | ### `errorHandler` 219 | - Default: (Return promise rejection with error) 220 | 221 | Function for custom global error handler. 222 | This example uses nuxt default error page. 223 | 224 | ```js 225 | axios: { 226 | errorHandler (error, { error }) { 227 | error('Request Error: ' + error) 228 | } 229 | }, 230 | ``` 231 | 232 | ## Helpers 233 | 234 | ### Fetch Style requests 235 | Axios plugin also supports fetch style requests with `$` prefixed methods: 236 | ```js 237 | // Normal usage with axios 238 | let data = (await $axios.get('...')).data 239 | 240 | // Fetch Style 241 | let data = await $axios.$get('...') 242 | ``` 243 | 244 | ### `setHeader(name, value, scopes='common')` 245 | Axios instance has a helper to easily set any header. 246 | 247 | Parameters: 248 | - **name**: Name of the header 249 | - **value**: Value of the header 250 | - **scopes**: Send only on specific type of requests. Defaults 251 | - Type: *Array* or *String* 252 | - Defaults to `common` meaning all types of requests 253 | - Can be `get`, `post`, `delete`, ... 254 | 255 | ```js 256 | // Adds header: `Authorization: 123` to all requests 257 | this.$axios.setHeader('Authorization', '123') 258 | 259 | // Overrides `Authorization` header with new value 260 | this.$axios.setHeader('Authorization', '456') 261 | 262 | // Adds header: `Content-Type: application/x-www-form-urlencoded` to only post requests 263 | this.$axios.setHeader('Content-Type', 'application/x-www-form-urlencoded', ['post']) 264 | 265 | // Removes default Content-Type header from `post` scope 266 | this.$axios.setHeader('Content-Type', false, ['post']) 267 | ``` 268 | 269 | ### `setToken(token, type, scopes='common')` 270 | Axios instance has an additional helper to easily set global authentication header. 271 | 272 | Parameters: 273 | - **token**: Authorization token 274 | - **type**: Authorization token prefix(Usually `Bearer`). 275 | - **scopes**: Send only on specific type of requests. Defaults 276 | - Type: *Array* or *String* 277 | - Defaults to `common` meaning all types of requests 278 | - Can be `get`, `post`, `delete`, ... 279 | 280 | ```js 281 | // Adds header: `Authorization: 123` to all requests 282 | this.$axios.setToken('123') 283 | 284 | // Overrides `Authorization` header with new value 285 | this.$axios.setToken('456') 286 | 287 | // Adds header: `Authorization: Bearer 123` to all requests 288 | this.$axios.setToken('123', 'Bearer') 289 | 290 | // Adds header: `Authorization: Bearer 123` to only post and delete requests 291 | this.$axios.setToken('123', 'Bearer', ['post', 'delete']) 292 | 293 | // Removes default Authorization header from `common` scope (all requests) 294 | this.$axios.setToken(false) 295 | ``` 296 | 297 | ## Dynamic API Backend 298 | Please notice that, `API_URL` is saved into bundle on build, CANNOT be changed 299 | on runtime! You may use [proxy](../proxy) module for dynamically route api requests to different backend on test/staging/production. 300 | 301 | **Example: (`nuxt.config.js`)** 302 | 303 | ```js 304 | { 305 | modules: [ 306 | '@nuxtjs/axios', 307 | '@nuxtjs/proxy' 308 | ], 309 | proxy: [ 310 | ['/api', { target: 'http://www.mocky.io', pathRewrite: { '^/api': '/v2' } }] 311 | ] 312 | } 313 | ``` 314 | 315 | Start Nuxt 316 | ``` 317 | [AXIOS] Base URL: http://localhost:3000/api | Browser: /api 318 | [HPM] Proxy created: /api -> http://www.mocky.io 319 | [HPM] Proxy rewrite rule created: "^/api" ~> "/v2" 320 | ``` 321 | 322 | Now you can make requests to backend: (Works fine in both SSR and Browser) 323 | ```js 324 | async asyncData({ app }) { 325 | // Magically makes request to http://www.mocky.io/v2/59388bb4120000dc00a672e2 326 | const nuxt = await app.$axios.$get('59388bb4120000dc00a672e2') 327 | 328 | return { 329 | nuxt // -> { nuxt: 'Works!' } 330 | } 331 | } 332 | ``` 333 | 334 | Details 335 | - `'@nuxtjs/axios'` 336 | - By default axios plugin sets base url to `http://[host]:[port]/api` which is `http://localhost:3000/api` 337 | 338 | - `'/api': 'http://www.mocky.io/v2'` 339 | - This line creates a server middleware to pass requests from `/api` to `http://www.mocky.io/v2` 340 | - We used `pathRewrite` to remove `/api` from starting of requests and change it to `/v2` 341 | - For more information and advanced usage please refer to [proxy](../proxy) docs. 342 | 343 | ## License 344 | 345 | [MIT License](./LICENSE) 346 | 347 | Copyright (c) 2017 Nuxt Community 348 | --------------------------------------------------------------------------------