Babel config / run commands file
Path: /.babelrc
The babel config file defines the presets used by babel to transpile the ES6 code. The babel transpiler is run by webpack via the babel-loader module configured in the webpack.config.js file below.
{
"presets": [
"env",
"stage-0"
]
}
Deploying the vue.js app to aws
This video shows how to setup a production ready web server from scratch on AWS, then deploy the example Vue.js Vuex app and configure it to run with a real Node.js MongoDB backend api. The tutorial used in the video is available at Vue.js Node.js on AWS – How to Deploy a MEVN Stack App to Amazon EC2.
Deploying the vue.js app to microsoft azure
For instructions on how to deploy the Vue.js app to Azure with a real backend api built with ASP.NET Core and SQL Server see Vue.js ASP.NET Core SQL on Azure – How to Deploy a Full Stack App to Microsoft Azure.
Npm package.json
Path: /package.json
The package.json file contains project configuration information including package dependencies which get installed when you run npm install. Full documentation is available on the npm docs website.
Pdo. подключаемся к mysql и пишем вспомогательные функции
Может, обратили внимание на строчку use PDO; в самом начале helpers.php? Она разрешит нам использовать в пространстве имен Helpers возможности pdo. Первой функцией будет подключение к базе.
Vue vuex helpers folder
Path: /src/_helpers
The helpers folder contains all the bits and pieces that don’t fit into other folders but don’t justify having a folder of their own.
Vue app component
Path: /src/app/App.vue
The app component is the root component for the vue tutorial application, it contains the outer html, routes and global alert notification for the tutorial app.
Vue app entrypoint
Path: /src/index.js
The root index.js file bootstraps the vue vuex tutorial application by rendering the App component into the #app div element defined in the main index html file above.
The tutorial app uses a fake / mock backend that stores data in browser local storage, to switch to a real backend api simply remove the fake backend code below the comment // setup fake backend.
The VeeValidate library is used for form validation on the login and registration pages.
import Vue from 'vue';
import VeeValidate from 'vee-validate';
import { store } from './_store';
import { router } from './_helpers';
import App from './app/App';
Vue.use(VeeValidate);
// setup fake backend
import { configureFakeBackend } from './_helpers';
configureFakeBackend();
new Vue({
el: '#app',
router,
store,
render: h => h(App)
});
Vue app feature folder
Path: /src/app
The app folder is for vue components and other code that is used only by the app component in the tutorial application.
Vue auth header
Path: /src/_helpers/auth-header.js
Vue helpers index
Path: /src/_helpers/index.js
The helpers index file groups all helper exports together so they can be imported in other parts of the app using only the folder path, and enables importing multiple helpers in a single statement (e.g. import { helper1, helper2, … } from ‘../_helpers’).
export * from './fake-backend';
export * from './router';
export * from './auth-header';
Vue home feature folder
Path: /src/home
The home folder is for vue components and other code that is used only by the home page component in the tutorial application.
Vue home page component
Path: /src/home/HomePage.vue
Vue login feature folder
Path: /src/login
The login folder is for vue components and other code that is used only by the login page component in the tutorial application.
Vue login page component
Path: /src/login/LoginPage.vue
Vue main index html
Path: /src/index.html
The main index html file contains the outer html for the whole tutorial application. When the app is started with npm start, Webpack bundles up all of the vue vuex code into a single javascript file and injects it into the body of the page.
Vue register feature folder
Path: /src/register
The register folder is for vue components and other code that is used only by the register page component in the tutorial application.
Vue register page component
Path: /src/register/RegisterPage.vue
Vue router
Path: /src/_helpers/router.js
Vue services folder
Path: /src/_services
Vue services index
Path: /src/_services/index.js
The services index file groups all service exports together so they can be imported in other parts of the app using only the folder path, and enables importing multiple services in a single statement (e.g. import { service1, service2, … } from ‘../_services’).
Vue webpack config
Path: /webpack.config.js
Webpack is used to compile and bundle all the project files so they’re ready to be loaded into a browser, it does this with the help of loaders and plugins that are configured in the webpack.config.js file. For more info about webpack check out the webpack docs.
The webpack config file also defines a global config object for the application using the externals property, you can use this to define different config variables for your development and production environments.
Vue.js vuex tutorial project structure
All source code for the Vue.js Vuex tutorial app is located in the /src folder. Inside the src folder there is a folder per feature (app, home, login, register) and a few folders for non-feature code that can be shared across different parts of the app (_helpers, _services, _store).
I prefixed non-feature folders with an underscore “_” to group them together and make it easy to distinguish between features and non-features, it also keeps the project folder structure shallow so it’s quick to see everything at a glance from the top level and to navigate around the project.
Click any of the below links to jump down to a description of each file along with it’s code:
Vuex account module
Path: /src/_store/account.module.js
Vuex alert module
Path: /src/_store/alert.module.js
The vuex alert module is in charge of the alert section of the centralised state store, it contains actions and mutations for setting a success or error alert message, and for clearing the alert.
In this module each alert action just commits a single mutation so it would be possible to commit the mutations directly from your vue components and get rid of the actions. However I prefer to dispatch actions from everywhere for consistency rather than dispatching actions for some things and committing mutations for others.
const state = {
type: null,
message: null
};
const actions = {
success({ commit }, message) {
commit('success', message);
},
error({ commit }, message) {
commit('error', message);
},
clear({ commit }) {
commit('clear');
}
};
const mutations = {
success(state, message) {
state.type = 'alert-success';
state.message = message;
},
error(state, message) {
state.type = 'alert-danger';
state.message = message;
},
clear(state) {
state.type = null;
state.message = null;
}
};
export const alert = {
namespaced: true,
state,
actions,
mutations
};
Vuex store
Path: /src/_store/index.js
This is the main vuex store file that configures the store with all of the above vuex modules.
Vuex store folder
Path: /src/_store
Испытания
Проверим то, что мы создали, предварительно запустив сервер приложения и сервер базы данных. А именно, если перейти по адресу
Маршруты api, файл budgetmanagerapi/app/routes/auth.js
Займёмся созданием маршрутов API. Для этого перейдём в папку
services/BudgetManagerAPI/app
и создадим в ней директорию
routes
, в которой создадим файл
auth.js
со следующим содержимым:
Настройка package.json
Перейдём в корневую директорию проекта, откроем
package.json
и добавим в него, сразу перед блоком
dependencies
, следующее:
Настройка сервера, файл services/index.js
После того, как мы справились с некоторыми из вспомогательных подсистем, займёмся настройкой сервера. Перейдите в папку
services
и откройте уже имеющийся в ней файл
index.js
. Добавьте в него следующее:
Общие настройки проекта settings.py
config = Config(".env")
DEBUG = config("DEBUG", cast=bool, default=False)
DATABASE_URL = config("DATABASE_URL", cast=str)
SECRET_KEY = config("SECRET_KEY", cast=Secret)
ALLOWED_HOSTS = config("ALLOWED_HOSTS", cast=CommaSeparatedStrings)
JWT_PREFIX = config("JWT_PREFIX", cast=str)
JWT_ALGORITHM = config("JWT_ALGORITHM", cast=str)
Для удобства использования вынесем переменные из файла .env в отдельный файл настроек.
Промежуточный слой для работы с jwt middleware.py
Поскольку Starlette еще достаточно молодой фреймворк, удобной «батарейки» JWT к нему еще не написано. Исправим этот недочет.
Работа с брендами. роутер brands
С брендами мы работаем абсолютно так же, как и с категориями. Те же операции, те же параметры, та же структура таблицы. Только название таблицы другое (brands) и поле названия бренда (brand). Я даже код копипастить не буду, возьмите в исходниках.
Работа с категориями. роутер categories
Сначала создадим папку routers, а в ней файл categories.php. Помните, в index.php мы запускали функцию route? Еще упоминали, что она все разрулит. Давайте посмотрим, каким образом
Работа с товарами. роутер products
Код в products.php очень похож на предыдущие, но с тремя отличиями:
1. Добавляется запрос GET /products/{id} – вытаскиваем данные по одному товару
2. Запрос GET /products/ поддерживает пагинацию и фильтрацию по id категории. Это достигается передачей необязательных get-параметров categoryId, offset и limit
3. При добавлении и редактировании товаров в теле запроса передается больше параметров. Не один title, а такой набор: title, categoryId, brandId, price и rating.
Никакой разницы нет, просто приходится делать больше проверок и sql-запросы будут длиннее.
Давайте я выложу всю портянку, а потом рассмотрим эти 3 пункта подробнее.
Ссылки
Полный код на Github:
Бекенд на Starlette
Фронтенд на Vue.js
Пример работы
Спасибо за внимание Удачных интеграций.
Структура проекта и установка зависимостей
Для начала создадим структуру папок для проекта, которая, в самом начале работы, должна выглядеть следующим образом:
Структура папок API
В ходе продвижения по материалу мы значительно расширим эту структуру.
Теперь нужно установить несколько зависимостей. Для этого перейдём в корневую папку проекта (здесь это focus-budget-manager) и, предварительно сформировав package.json командой npm init, выполним следующую команду:
npm i --save express body-parser mongoose consign cors bcrypt jsonwebtoken morgan passport passport-jwt module-alias
Рассмотрим некоторые из этих зависимостей и их роль в проекте:
Тестирование приложения с использованием postman
Для начала подключимся к конечной точке
setup
для создания учётной записи администратора. В интерфейсе Postman это будет выглядеть так:
Файл budgetmanagerapi/app/api/auth.js
Теперь начинаем создавать некоторые из методов API. Перейдём в папку
BudgetManagerAPI/app
, создадим в ней директорию
api
, а в ней — файл
auth.js
. Запишем в него следующее:
const mongoose = require('mongoose'),
jwt = require('jsonwebtoken'),
config = require('@config');
Обратите внимание на то, что, благодаря использованию модуля
module_alias
мы сделали код чище. Иначе пришлось бы писать примерно следующее:
config = require('./../../config);
Теперь, после подключения пакетов, сделаем в том же файле следующее:
Файл budgetmanagerapi/app/setup/index.js
После настройки псевдонимов перейдём в папку
BudgetManagerAPI/app
и создадим новую папку
setup
, а в ней — файл
index.js
. Добавим в него следующее:
Файл budgetmanagerapi/config/app.js
В директории
BudgetManagerAPI/config
создадим файл
app.js
. Для начала подключим зависимости:
const express = require('express'),
app = express(),
bodyParser = require('body-parser'),
mongoose = require('mongoose'),
morgan = require('morgan'),
consign = require('consign'),
cors = require('cors'),
passport = require('passport'),
passportConfig = require('./passport')(passport),
jwt = require('jsonwebtoken'),
config = require('./index.js'),
database = require('./database')(mongoose, config);
В строке
passportConfig = require('./passport')(passport)
мы импортируем конфигурационный файл для
passport
, передавая
passport
в качестве аргумента, так как в
passport.js
имеется такая команда:
Благодаря такому подходу мы можем работать с passport внутри файла passport.js без необходимости подключать его.
Далее, в файле app.js, начинаем работу с пакетами и устанавливаем секретный ключ:
app.use(express.static('.'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(morgan('dev'));
app.use(cors());
app.use(passport.initialize());
app.set('budgetsecret', config.secret);
Как вариант, вместо использования пакета
cors
, можно сделать следующее:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
Файл budgetmanagerapi/config/database.js
В папке
BudgetManagerAPI/config
создадим файл
database.js
, который ответственен за работу с базой данных. Добавим в этот файл следующее:
module.exports = (mongoose, config) => {
const database = mongoose.connection;
mongoose.Promise = Promise;
mongoose.connect(config.database, {
useMongoClient: true,
promiseLibrary: global.Promise
});
database.on('error', error => console.log(`Connection to BudgetManager database failed: ${error}`));
database.on('connected', () => console.log('Connected to BudgetManager database'));
database.on('disconnected', () => console.log('Disconnected from BudgetManager database'));
process.on('SIGINT', () => {
database.close(() => {
console.log('BudgetManager terminated, connection closed');
process.exit(0);
})
});
};
Тут мы сначала переключили
mongoose
на использование стандартного объекта
Promise
. Если этого не сделать, можно столкнуться с предупреждениями, выводимыми в консоль. Затем мы создали стандартное подключение
mongoose
Файл budgetmanagerapi/config/index.js
Создадим в папке
BudgetManagerAPI/config
файл
index.js
и внесём в него следующий код:
module.exports = {
secret: 'budgetsecret',
session: { session: false },
database: 'mongodb://127.0.0.1:27017/budgetmanager'
}
Этот файл содержит параметры подключения к базе данных и секретный ключ, который мы используем для создания JWT-токенов.
Здесь предполагается работа с локальным сервером MongoDB. При этом в строке 127.0.0.1:27017 можно использовать localhost. Если хотите, можете работать с облачной базой данных MongoDB, созданной, например, средствами MLabs.
Файл budgetmanagerapi/config/passport.js
После того, как модель
Файл с переменными .env
Объявим здесь переменные, которые нам в дальнейшем понадобятся для работы:
Running the tutorial example with a real backend api
The boilerplate code uses a fake / mock backend by default that uses browser local storage for managing application data, to switch to a real backend api you just have to remove a couple of lines of code from the main vue entry file /src/index.js below the comment // setup fake backend.
You can build your own backend api or start with one of the below options:
Итоги
На этом мы завершаем первую часть данной серии. Здесь вы узнали о том, как, с чистого листа, создать Node.js-приложение и настроить простую JWT-аутентификацию. В следующей части приступим к разработке пользовательского интерфейса приложения с использованием Vue.js.
Уважаемые читатели! Как по-вашему, подойдёт ли способ аутентификации пользователей, предложенный автором, для использования в продакшне?
Vue fake / mock backend
Path: /src/_helpers/fake-backend.js
The fake backend is used for running the tutorial example without a server api (backend-less). It monkey patches the fetch() function to intercept certain api requests and mimic the behaviour of a real api. Any requests that aren’t intercepted get passed through to the real fetch() function.
I created it so I could focus the tutorial on the Vue Vuex code and not worry about the backend, and also to make it work on StackBlitz.