Geekbrains Node JS. Урок 4. Фреймворк Express


Express закрывает около 80% всех вопросов по созданию приложений на node.js

Устанавливаем express

npm i express

Подключаем, создаём приложение, создаём сервер

const express = require("express");
const app = express();
app.get("/", (req, res) => {
  res.send("Hello world");
});
app.listen(3000, () => {
  console.log("Server has been started!");
});

По адресу http://localhost:3000/ наш сервер

Рассмотрим функцию app.get
Это get-запрос к серверу. Такой запрос отправляем, когда просто открываем страницу.

Первый параметр - ссылка на ту страницу, которую открываем. Косой слэш это главная страница - http://localhost:3000/. А, например, адрес '/user' это страница http://localhost:3000/user

Второй параметр - функция с двумя параметрами reqres
req - request - запрос, который мы отправляем к серверу.
res - responce - ответ, который сервер возвращает нам

request содержит параметры запроса к серверу
Например, если вывести в консоль req.query

app.get("/user", (req, res) => {
  console.log(req.query);
  res.send("Hello world");
});

И перейти по ссылке
http://localhost:3000/?id=1&name=ivan

В консоли будет объект { id: '1', name: 'ivan' }

Получить параметры POST-запроса немного сложнее
Вначале пишем строку

app.use(express.json());
Она означает что мы подключили модуль express.json() который умеет считывать тело POST-запроса. Этот модуль встроен в express, поэтому устанавливать его не нужно. Механизм его работы называется  middleware - промежуточный обработчик.

Затем пишем сам запрос

app.post('/users', (req, res) => {
  console.log(req.body);
  res.send("Ok");
});

Затем устанавливаем https://www.postman.com/downloads/
Авторизуемся. Отправляем POST-запрос


И в консоли видим объект req.body { id: 1, name: 'Vasya' }

Есть и другие способы отправить POST-запрос серверу.
Один из них, чтобы клиент с сервером взаимодействовали через JSON и запрос отправлять при помощи fetch

fetch('/users', {
  method: POST,
  body: JSON.stringify({ id: 1, name: 'Vasya' })
}).then(response => console.log(response.text()))

Можно отправлять POST-запросы при помощи формы

Для этого
1) Подключаем промежуточный обработчик

app.use(express.urlencoded({ extended: false }));
express.urlencoded() - это метод, встроенный в express для распознавания входящего объекта запроса в виде строк или массивов.
Альтернативой ему с той же целью можно использовать body-parser

2) создаём форму, указывая method="POST" action="/settings" или другой эндпойнт, который в app.js будет обрабатывать пришедший запрос

3) полям формы (input) обязательно добавляем имена name

4) в app.js пишем код

app.post('/settings', (req, res) => {
console.log(req.body);
});

req.body содержит то, что мы отправили через форму

Динамические адреса

Рассмотрим как создать отдельную страницу для каждого пользователя.
Для этого пишем запрос

app.get('/users/:id', (req, res) => {
  console.log(req.params);
});

После двоеточия может быть любое осмысленное имя переменной. А её значение находится в req.params

Переходим по ссылке http://localhost:3000/users/vasya
В консоли { id: 'vasya' }
Или можно получить console.log(req.params.id)
В консоли 'vasya'

Параметров может быть несколько. Тогда их пишут один за другим

app.get('/users/:id/:username/:age', (reqres=> {
  console.log(req.params);
});

Переходим по ссылке http://localhost:3000/users/2/vasya/24
В консоли { id: '2', username: 'vasya', age: '24' }

Несколько параметров почти никогда не используются, но вообще такая возможность присутствует
Параметры могут использоваться в запросах любого типа, но в запросах типа GET встречаются немного чаще.

Middleware


middleware указываются в методе app.use перед всеми запросами
Их задача - предварительная обработка запроса. Они находятся между запросов и его обработчиком и срабатывают раньше всех.
middleware могут использоваться готовые или создаваться свои.

Синтаксис middleware

app.use((reqresnext=> {
  console.log(1);
})

в таком виде  middleware сработает на любой запрос вообще, независимо от метода, эндпойнта (адреса) на который он был отправлен
Можно ограничить middleware только одним адресом

app.use('/users', (reqresnext=> {
  console.log(2);
})

Здесь будут обрабатываться все запросы по адресу, содержащему /users в том числе и /users/:id

Если нужно обработать только запросы /users пишут так

app.all('/users', (reqresnext=> {
  console.log(3);
})

Срабатывают middleware от самых общих к самым частным. Если запустить их все, в консоль выведется 1 2 3 (на самом деле у меня они работают по порядку появления их в коде)

app.use('/users', (reqresnext=> {
  console.log(2);
  next()
})
app.use((reqresnext=> {
  console.log(1);
  next()
})
app.all('/users', (reqresnext=> {
  console.log(3);
  next()
})

next() - функция для перехода к следующему обработчику

Шаблонизация

Шаблонизация лежит в основе создания монолитной архитектуры, есть ещё вариант создания микроархитектуры

Существует много шаблонизаторов, один из распространённых handlebars, известный своим "усатым" синтаксисом, в котором каждая команда берётся в две двойные кавычки, примерно так же они оформляются в angular и vue

Устанавливаем handlebars и consolidate. Последний нужен для упрощения подключения handlebars и многих других шаблонизаторов (но можно подключить и без него, просто с ним проще)

npm i handlebars consolidate

Подключаем handlebars

const path = require('path');
const consolidate = require('consolidate');

app.engine('hbs', consolidate.handlebars);
app.set('view engine''hbs');
app.set('views', path.resolve(__dirname, '..''views'));

Модуль path нужен для установки путей, которые будут работать на любом устройстве и в любой операционной системе.

hbs - это расширение файлов handlebars
views - папка файлы которой будут рендерится

Создаём папку views в ней файл user.hbs
В нём код

<div class="user">
  <h2>{{username}}</h2>
  {{#if age}}
  <h2>{{age}}</h2>
  {{/if}}
  <ul>
    {{#each achievements}}
    <li>{{this}}</li>
    {{/each}}
  </ul>
</div>

handlebars  не только умеет работать с динамическими данными, но и позволяет добавлять логику

В файле app.js создадим объект users

const users = {
  vasya: {
    username: 'Vasya Pupkin',
    age: 32,
    achievements: ['main leader''active member']
  },
  kolya: {
    username: 'Kolya Pupkin',
    achievements: ['unior''sportsman']
  }
}

app.get('/users/:username', (reqres=> {
  const userData = users[req.params.username];
  res.render('user', userData);
});

В res.render указываем название шаблона, который используем для отображения данных - user.hbs и название переменной. из которой получаем данные
Теперь по ссылке http://localhost:3000/users/vasya отобразятся данные users.vasya

Домашнее задание. Создать веб-интерфейс, который позволяет получать данные из одного из нескольких сайтов (выбор возможен через форму) и указывать количество новостей на страницу.