Работать с базой данных (CRUD) через REST запросы, при этом добавление/удаление/изменение данных доступно только залогиненному через ГУГЛ, ВК или Твиттер пользователю в роли администратора — не ясно
Придется ли использовать в таком случае backend на каком-нибудь php фреймворке типа Laravel или yii2?
Можно ли обойтись только фреймворками для node.js для таких вещей как CRUD + кэширование REST ответов от БД + кэширование изображений + сжатие страниц по типу gzip?
Являются ли фреймворки на node.js более медленными по сравнению с php фреймворком на nginx в контексте запросов к бд и обработки данных?
demo-app/views/index.jade
node ./bin/www
npm start
app.get('/ab(cd)?e', function(req, res) {
res.send('ab(cd)?e'); // здесь может быть что-нибудь, например: покажи страницу с такой-то картинкой
});
...
const v4 = require('node-uuid').v4
const jwt = require('jsonwebtoken')
...
router.post('/signin', (req, res, next) => {
// валидация, например...
if (errors) {
return res.status(400).json({ errors })
} else {
// поиск юзера в базе, сравнение хэша и прочие необходимые операции
...
// допустим все ок, нужно ответить токеном
// генерируем необходимые опции и сам токен
const payload = {
_id: user._id,
iss: 'http://localhost:3000',
permissions: 'poll',
}
const options = {
expiresIn: '7d',
jwtid: v4(),
}
const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
jwt.sign(payload, secret, options, (err, token) => {
// отвечаем токеном, для будущих запросов с клиента
return res.json({ data: token })
})
...
})
module.exports = router;
...
const jwt = require('jsonwebtoken')
const Poll = require('../models/poll')
...
const requireToken = (req,res,next) => {
const token = req.headers['x-api-key']
const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
jwt.verify(token, secret, (err, decoded) => {
if (err) {
return res.status(401).json({ error: err.message })
}
req.params.userId = decoded._id
next()
})
}
...
// обратите внимание на requireToken - функция вызывается при каждом обращении к роуту
// то есть при каждом PUT запросе по адресу (например: PUT api/v1/products/1238914)
// будет вызываться requireToken
router.put('/:id', requireToken, (req, res, next) => {
const { productId } = req.body
const userId = req.params.userId
Poll.findById(req.params.id)
.populate({ path: 'products' })
.exec((err, poll) => {
// ... необходимые действия в базе, в процессе успешного зачтения голоса...
}
})
export function login(data) {
return dispatch => {
dispatch({ type: LOGIN_REQUEST })
// request в данном случае - https://github.com/KyleAMathews/superagent-bluebird-promise
return request.post(`${API_ROOT_V1}/auth/signin`)
.send(data)
.then(res => {
if (!res.ok) {
dispatch({ type: LOGIN_FAILURE })
} else {
dispatch({
type: LOGIN_SUCCESS,
data: res.body.data,
})
//сохранение токена в localStorage
localStorage.setItem('cks_token', res.body.data)
}
}, err => {
dispatch({ type: LOGIN_FAILURE })
})
}
}
export function vote(productId, voteId) {
return dispatch => {
dispatch({ type: POLL_VOTE_REQUEST })
return request.put(`${API_ROOT_V1}/api/v1/vote/${voteId}`)
.set('X-API-Key', localStorage.getItem('cks_token')) // установка ТОКЕНА в заголовок 'X-API-Key'
.send({ productId })
.then(res => {
if (!res.ok) {
dispatch({ type: POLL_VOTE_FAILURE })
} else {
dispatch({
type: POLL_VOTE_SUCCESS,
data: normalize(res.body.data, schema.poll),
})
}
}, err => {
dispatch({ type: POLL_VOTE_FAILURE })
})
}
}
import fetch from 'isomorphic-fetch'
...
const defaultHeaders = {
Accept: 'application/json',
'Content-Type': 'application/json',
}
function buildHeaders() {
const authToken = localStorage.getItem('TOKEN')
return { ...defaultHeaders, Authorization: authToken }
}
...
export function httpPost(url, data) {
const body = JSON.stringify(data)
return fetch(url, {
method: 'post',
headers: buildHeaders(),
body: body,
})
.then(... код оработки запроса ...)
}
...
<Provider store={store}>
<Router history={routerHistory}>
{configRoutes(store)} // Роуты создаются функцией, чтобы можно было использовать внутри нее store.getState()
</Router>
</Provider>
...
export default function configRoutes(store) {
function _ensureAuthenticated(nextState, replace, callback) {
const { dispatch } = store
const { session } = store.getState()
const { currentUser } = session
let nextUrl
if (!currentUser && localStorage.getItem('cks.token')) {
dispatch(getCurrentAccount())
} else if (!localStorage.getItem('cks.token')) {
replace('/signin')
}
callback()
}
return (
<Route path='/' component={App}>
<Route path='/signin' component={SigninContainer} />
<Route path='/signup' component={SignupContainer} />
<Route path='/locked' component={AuthenticatedContainer} onEnter={_ensureAuthenticated}>
<Route component={LockedArea}>
<Route path='/locked/a' component={A} />
<Route path='/locked/b/:id' component={B} />
<Route path='/locked/c' component={C} />
</Route>
</Route>
</Route>
)
screen
meteor
, затем выходите из скрина (обычно это ctrl + A,D ) и у вас "сессия" в той виртуальной вкладке остается висеть. Чтобы снова к ней присоединиться, нужно написать screen -R
. Ну или просто почитайте подробнее про screen. какой самый быстрый и оптимальный способ отправки данных на сервер: обычный запрос (POST), веб-сокеты... вряд ли что-то еще.
а также как создать такой сервер и базу и мини API для приёма и записи данных
const express = require('express')
const router = express.Router()
const User = require('../models/user')
const v4 = require('node-uuid').v4
const jwt = require('jsonwebtoken')
router.post('/signup', (req, res, next) => {
req.check('email', 'Please enter a valid email').len(1).isEmail()
req.check('password', 'Please enter a password with a length between 4 and 34 digits').len(4, 34)
const errors = req.validationErrors()
if (errors) {
return res.status(400).json({ errors })
} else {
User.hashPassword(req.body.password, (err, passwordHash) => {
if (err) {
return res.status(400).json({ error: err.message })
}
const user = new User({
name: req.body.name,
nickname: req.body.nickname,
email: req.body.email,
password: req.body.password,
})
user.passwordHash = passwordHash
user.save((err, item) => {
if (err) {
return res.status(400).json({ error: err.message })
}
const payload = {
_id: item._id,
iss: 'http://localhost:3000',
permissions: 'poll',
}
const options = {
expiresIn: '7d',
jwtid: v4(),
}
const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
jwt.sign(payload, secret, options, (err, token) => {
return res.json({ data: token })
})
})
})
}
})
router.post('/signin', (req, res, next) => {
req.check('email', 'Please enter a valid email').len(1).isEmail()
req.check('password', 'Please enter a password with a length between 4 and 34 digits').len(4, 34)
const errors = req.validationErrors()
const password = req.body.password
if (errors) {
return res.status(400).json({ errors })
} else {
User.findOne({ email: req.body.email }, (err, user) => {
if (err) {
return res.status(400).json({ error: err.message })
}
if (!user) {
return res.status(400).json({ error: 'User not found' })
}
User.comparePasswordAndHash(password, user.passwordHash, (err, areEqual) => {
if (err) {
return res.status(400).json({ error: err.message })
}
if (!areEqual) {
return res.status(400).json({ error: 'Wrong password' })
}
const payload = {
_id: user._id,
iss: 'http://localhost:3000',
permissions: 'poll',
}
const options = {
expiresIn: '7d',
jwtid: v4(),
}
const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
jwt.sign(payload, secret, options, (err, token) => {
return res.json({ data: token })
})
})
})
}
})
module.exports = router;
const payload = {
_id: item._id,
iss: 'http://localhost:3000',
permissions: 'poll',
}
app.engine('handlebars', exphbs({defaultLayout: 'main'}));
app.set('view engine', 'hbs'); //в офф.доке используют расширение handlebars
Как на счет jwt ?
const express = require('express')
const router = express.Router()
const User = require('../models/user')
const v4 = require('node-uuid').v4
const jwt = require('jsonwebtoken')
router.post('/signup', (req, res, next) => {
req.check('email', 'Please enter a valid email').len(1).isEmail()
req.check('password', 'Please enter a password with a length between 4 and 34 digits').len(4, 34)
const errors = req.validationErrors()
if (errors) {
return res.status(400).json({ errors })
} else {
User.hashPassword(req.body.password, (err, passwordHash) => {
if (err) {
return res.status(400).json({ error: err.message })
}
const user = new User({
name: req.body.name,
nickname: req.body.nickname,
email: req.body.email,
password: req.body.password,
})
user.passwordHash = passwordHash
user.save((err, item) => {
if (err) {
return res.status(400).json({ error: err.message })
}
const payload = {
_id: item._id,
iss: 'http://localhost:3000',
permissions: 'poll',
}
const options = {
expiresIn: '7d',
jwtid: v4(),
}
const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
jwt.sign(payload, secret, options, (err, token) => {
return res.json({ data: token })
})
})
})
}
})
router.post('/signin', (req, res, next) => {
req.check('email', 'Please enter a valid email').len(1).isEmail()
req.check('password', 'Please enter a password with a length between 4 and 34 digits').len(4, 34)
const errors = req.validationErrors()
const password = req.body.password
if (errors) {
return res.status(400).json({ errors })
} else {
User.findOne({ email: req.body.email }, (err, user) => {
if (err) {
return res.status(400).json({ error: err.message })
}
if (!user) {
return res.status(400).json({ error: 'User not found' })
}
User.comparePasswordAndHash(password, user.passwordHash, (err, areEqual) => {
if (err) {
return res.status(400).json({ error: err.message })
}
if (!areEqual) {
return res.status(400).json({ error: 'Wrong password' })
}
const payload = {
_id: user._id,
iss: 'http://localhost:3000',
permissions: 'poll',
}
const options = {
expiresIn: '7d',
jwtid: v4(),
}
const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
jwt.sign(payload, secret, options, (err, token) => {
return res.json({ data: token })
})
})
})
}
})
module.exports = router;
const mongoose = require('mongoose')
const bcrypt = require('bcrypt')
const Schema = mongoose.Schema
let bcrypt_cost = 12
const userSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true },
passwordHash: String,
})
userSchema.statics.hashPassword = (passwordRaw, cb) => {
if (process.env.NODE_ENV === 'test') {
bcrypt_cost = 1
}
bcrypt.hash(passwordRaw, bcrypt_cost, cb)
}
userSchema.statics.comparePasswordAndHash = (password, passwordHash, cb) => {
bcrypt.compare(password, passwordHash, cb)
}
const User = mongoose.model('User', userSchema)
module.exports = User
var Schema = mongoose.Schema
ReferenceError: Schema is not defined
var Schema = ...
, следовательно вы не можете использовать эту переменную, так как ее просто не существует. Она никак не requir'ится в ваш файл, вы никак ее не определяете...