Создание сайтов в Селидово, ДНР. Как перенести ваше приложение с Express на Fastify

 
 

Express уже давно является самой популярной средой для разработки веб-приложений с помощью Node.js. К сожалению, в последние годы эта структура не получила активного развития. Это означает, что он не поддерживает современные функции JavaScript. Тем временем появилось несколько новых фреймворков, использующих другой подход к разработке приложений Node.js. Одним из таких фреймворков является Fastify.

В этой статье мы рассмотрим, что делает Fastify привлекательной альтернативой для разработки веб-приложений с помощью Node.js. Мы узнаем, как избежать необходимости переписывать наши существующие приложения Express с нуля и вместо этого поэтапно перевести их на использование Fastify. К тому времени, когда мы закончим, вы сможете уверенно перенести свои существующие приложения Express и начать использовать преимущества платформы Fastify.

Есть несколько требований для того, чтобы следовать вместе с этой статьей:

Вам нужно уметь создавать базовое приложение Express, определять маршруты и настраивать промежуточное ПО.

Вам нужно уметь запускать команды в терминале.

Вам потребуется установить Node.js ≥ v14.13.0. Это дает нам хорошую поддержку модулей ECMAScript (ES) и позволяет использовать await верхнего уровня. В примерах кода в этой статье используется синтаксис модуля ES (import/ export).

Весь пример кода в этой статье доступен на GitHub для просмотра, загрузки и экспериментов.

На моем сайте также есть видеоверсия этого поста.

Каковы преимущества перехода с Express на Fastify?

Если вам удобно создавать приложения Node.js с помощью Express, вам может быть интересно, в чем преимущества переноса существующих приложений Express на Fastify. Вот несколько веских причин, чтобы подумать о переезде:

Проверка и выход из коробки. Эти функции обычно требуются при создании веб-приложений. При использовании Fastify нет необходимости выбирать и интегрировать библиотеки для этих задач, так как он их нам предоставляет. Мы узнаем больше об этих функциях позже в этой статье.

Встроенная поддержка асинхронного кода. Fastify изначально обрабатывает промисы и поддерживает async/ await. Это означает, что маршруты будут ловить для нас неперехваченные отклоненные промисы. Это позволяет нам безопасно писать асинхронный код. Это также позволяет нам делать изящные вещи, например, автоматически отправлять возвращаемое значение из функции обработчика маршрута в качестве тела ответа:

app.get («/user/: id», async (request) => await getUser (request.params.id));

Автоматический разбор и сериализация JSON. Нам не нужно настраивать Fastify для разбора тел запросов JSON или для сериализации объектов в формате JSON для ответов. Он обрабатывает все это автоматически для нас:

app.get («/user/: id», async (request, reply) => {

const name = request.body.name;

reply.send ({ user: { name } }) ;

}) ;

Дружественный разработчик. Благодаря явным и выразительным API, а также отличной поддержке TypeScript Fastify был разработан с учетом опыта разработчиков.

Это быстро. Мы никогда не хотим, чтобы фреймворк стал источником узких мест в производительности наших приложений. Хорошей новостью является то, что Fastify был создан, чтобы быть высокопроизводительным. Тесты Fastify показывают, как он сравнивается с другими веб-фреймворками Node.js.

В активной разработке. Фреймворк Fastify активно развивается. Есть регулярные выпуски с улучшениями и исправлениями ошибок/безопасности.

Как уверенно мигрировать API

Мы хотим быть уверены, что наше приложение по-прежнему работает должным образом после того, как оно было перенесено в Fastify. Одна из вещей, которая может помочь нам обнаружить ошибки или выявить непреднамеренные изменения, — это интеграционные тесты API.

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

Если мы пишем интеграционные тесты API для приложения Express, мы хотим иметь возможность запускать те же самые тесты после переноса приложения на Fastify. При написании интеграционных тестов для API необходимо учитывать несколько ключевых моментов:

Они не должны быть привязаны к определенному фреймворку. Мы хотим иметь возможность запускать одни и те же тесты до и после миграции без необходимости изменять тесты или какие-либо библиотеки, которые мы используем для них.

Держите их простыми. Как минимум, интеграционные тесты должны делать запросы к конечным точкам, которые предоставляет API, и проверять, возвращается ли ответ, но, как правило, не более того. Мы можем захотеть проверить определенные коды состояния HTTP или заголовки ответов, но мы должны стараться сделать тесты максимально простыми.

Выберите инструменты, которые вам удобны. Существует множество различных инструментов, которые могут помочь нам в создании и запуске тестов API, но важно использовать удобные инструменты. Чтобы написать эффективные интеграционные тесты, нам нужно иметь возможность делать HTTP-запросы и делать утверждения в отношении ответов нашего API. В общем, нам не нужно много библиотек или инструментов, чтобы это работало.

Мы не будем вдаваться в детали реализации интеграционных тестов API в этой статье, но вы должны подумать о том, чтобы написать их, прежде чем приступать к миграции фреймворка.

Переход с Express на Fastify с помощью fastify-express

Идея переноса существующего приложения Express на совершенно другую платформу может показаться довольно сложной. К счастью, команда Fastify создала плагин fastify-express, который может упростить миграцию.

Плагин fastify-expressдобавляет полную совместимость Express с Fastify. Он предоставляет use () метод, который мы можем использовать для добавления промежуточного ПО Express и маршрутов на наш сервер Fastify. Это дает нам возможность постепенного переноса частей существующего приложения Express на Fastify.

Вот пример экспресс-маршрутизатора:

// src/routes.js

const router = express.Router () ;

router.get («/: user_id», function getUser (request, response, next) {

response.json ({}) ;

}) ;

export default router;

Затем мы можем fastify-expressдобавить наш существующий маршрутизатор Express в экземпляр сервера Fastify:

// src/server.js

import Fastify from «fastify»;

import ExpressPlugin from «fastify-express»;

import routes from «. /routes.js»;

const fastify = Fastify () ;

await fastify.register (ExpressPlugin) ;

fastify.use («/user», routes) ;

await fastify.listen (3000) ;

Мы подробно рассмотрим, как все это работает, когда начнем перенос нашего приложения на Fastify чуть позже.

Важно знать, что использование fastify-expressплагина не является долгосрочным решением. Если мы хотим получить все преимущества Fastify, в какой-то момент нам потребуется перенести код нашего приложения, специфичного для Express. Однако fastify-expressплагин предоставляет нам возможность поэтапного перехода на Fastify.

Наш пример экспресс-приложения

Мы собираемся создать пример приложения Express, а затем перенести его для использования платформы Fastify. Давайте теперь посмотрим на код для него.

Требуемые зависимости

Сначала создадим новый проект:

mkdir express-to-fastify-migration

cd express-to-fastify-migration

npm init -y

Затем мы запустим эту команду в нашем терминале, чтобы установить зависимости, которые потребуются нашему приложению Express:

npm install express cors

Наконец, откройте package.jsonи добавьте следующую строку над scriptsразделом:

«type»: «module»,

Это позволит нам загружать модули ES в наше приложение.

Модуль маршрутизатора

Мы собираемся создать экземпляр маршрутизатора Express, чтобы помочь нам инкапсулировать наши маршруты и промежуточное ПО. Маршрутизаторы в Express можно использовать, чтобы помочь нам организовать наше приложение в отдельные модули. Например, у нас может быть один маршрутизатор для /userмаршрутов и другой маршрутизатор для /addressмаршрутов. Позже мы увидим, как это может помочь нам поэтапно перенести наше приложение Express на Fastify.

Давайте создадим экземпляр маршрутизатора и добавим к нему промежуточное ПО:

// src/routes.js

import express from «express»;

import cors from «cors»;

const router = express.Router () ;

router.use (express.json ());

router.use (cors ({ origin: true }));

В приведенном выше коде мы настроили два примера промежуточного программного обеспечения Express:

экспресс.json (). Эта промежуточная функция встроена в Express. Он обрабатывает тела запросов JSON.

кор. Это промежуточное ПО помогает нам добавлять заголовки CORS в ответы API. Это позволит вызывать наш API с веб-страницы.

Эти инструменты промежуточного программного обеспечения будут запускаться для любых запросов к маршрутам, которые мы определяем на этом маршрутизаторе.

Теперь, когда мы настроили промежуточное ПО, мы можем добавить первый маршрут к нашему маршрутизатору:

// src/routes.js

router.post («/», function createUser (request, response, next) {

const newUser = request.body;

if (! newUser) {

return next (new Error («Error creating user»));

}

response.status (201).json (newUser) ;

}) ;

В реальном приложении функция обработчика маршрута, описанная выше, будет проверять полученные данные, а затем вызывать базу данных для создания новой записи пользователя. В этом примере мы отправляем полученные данные в виде тела ответа.

Теперь мы добавим маршрут для получения пользователя:

// src/routes.js

router.get («/: user_id», function getUser (request, response, next) {

const user = {

id: request.params.user_id,

first_name: «Bobinsky»,

last_name: «Oso»,

};

response.json (user) ;

}) ;

Как и в случае с POSTмаршрутом, вышеприведенный обработчик маршрута обычно вызывает базу данных для получения пользовательских данных, но для этого примера мы жестко запрограммировали объект для отправки в теле ответа.

Наконец, мы экспортируем routerобъект, чтобы его можно было импортировать в другой модуль:

// src/routes.js

export default router;

Модуль приложения

Теперь мы собираемся создать модуль приложения:

// src/app.js

import express from «express»;

import routes from «. /routes.js»;

export default function buildApp () {

const app = express () ;

app.use («/user», routes) ;

return app;

}

В этом модуле мы определяем функцию, которая создает новый экземпляр сервера Express. Затем мы добавляем наш объект маршрутизатора в экземпляр сервера.

Серверный модуль

Наконец, мы создадим серверный модуль. Этот модуль использует buildApp () функцию, которую мы определили в нашем модуле приложения, для создания нового экземпляра сервера Express. Затем он запускает наш сервер Express, настроив его на прослушивание порта 3000:

// src/server.js

import buildApp from «. /app.js»;

const express = buildApp () ;

express.listen (3000, () => {

console.log («Example app listening at http: //localhost:3000») ;

}) ;

Запускаем наше приложение

Теперь у нас есть полностью работающее приложение Express, которое мы можем запустить в нашем терминале:

node src/server.js

В отдельном терминале мы можем сделать запрос к API с помощью cURL, чтобы подтвердить, что он работает:

curl —verbose —request GET \

—url http: //localhost:3000/user/3d395cb4−531c−4989-b8ed-9cc75198187e \

—header 'Origin: http: //example-origin.com’

Мы должны получить ответ, который выглядит следующим образом:

< HTTP/1.1 200 OK

< X-Powered-By: Express

< Access-Control-Allow-Origin: http://example-origin.com

< Vary: Origin

< Content-Type: application/json; charset=utf-8

<

{«id»:«3d395cb4−531c−4989-b8ed-9cc75198187e»,«first_name»:«Bobinsky»,«last_name»:"Oso"}

Миграция нашего приложения с Express на Fastify

Теперь, когда у нас есть полнофункциональное приложение Express, мы собираемся перенести его на использование платформы Fastify.

Требуемые зависимости

Нам нужно установить три зависимости:

фреймворк Fastify

плагин fastify- express

плагин fastify-cors — это порт corsпромежуточного программного обеспечения Express, которое уже используется в нашем приложении.

Давайте запустим эту команду в нашем терминале, чтобы установить их:

npm install fastify-expressfastify-cors

Вы можете просмотреть различия этих изменений кода на GitHub.

Рефакторинг нашего модуля приложения

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

импортировать fastifyи fastify-expressвместоexpress

создать экземпляр сервера Fastify вместо экземпляра сервера Express

используйте fastify-expressплагин, чтобы добавить наш объект маршрутизатора Express на сервер

Вот как это выглядит после внесения этих изменений:

// src/app.js

import Fastify from «fastify»;

import ExpressPlugin from «fastify-express»;

import routes from «. /routes.js»;

export default async function buildApp () {

const fastify = Fastify ({

logger: true,

}) ;

await fastify.register (ExpressPlugin) ;

fastify.use («/user», routes) ;

return fastify;

}

Вы можете просмотреть различия этих изменений кода на GitHub.

Вы заметите в приведенном выше коде, что мы передаем параметр регистратора при создании нашего экземпляра сервера Fastify. Это включает встроенную функцию ведения журнала Fastify. Мы узнаем больше об этом позже.

Рефакторинг нашего серверного модуля

Теперь нам нужно изменить наш серверный модуль для работы с экземпляром сервера Fastify:

// src/server.js

import buildApp from «. /app.js»;

const fastify = await buildApp () ;

try {

await fastify.listen (3000) ;

} catch (error) {

fastify.log.error (error) ;

process.exit (1) ;

}

Вы можете просмотреть различия этих изменений кода на GitHub.

Поскольку Fastify имеет встроенную поддержку обещаний, в приведенном выше коде мы можем использовать, awaitа затем перехватывать и регистрировать любые ошибки с помощью встроенной функции ведения журнала Fastify.

Следующие шаги

Наше приложение теперь использует Fastify для маршрутизации запросов и отправки ответов. Он полностью функционален, но Express все еще используется на наших маршрутах. Чтобы полностью отказаться от Express, нам также необходимо перенести наши маршруты для использования Fastify.

Рефакторинг нашего модуля маршрутов

Маршруты в нашем приложении Express инкапсулированы в маршрутизатор Express. Мы собираемся преобразовать этот маршрутизатор в подключаемый модуль Fastify. Плагины — это функция Fastify, которая позволяет нам инкапсулировать маршруты и любые связанные с ними функции.

Мы начнем рефакторинг нашего модуля маршрутов (src/routes.js), удалив некоторые строки, относящиеся к Express:

— import express from «express»

— const router = express.Router () ;

— router.use (express.json ());

Затем нам нужно изменить экспорт модуля по умолчанию, чтобы он был asyncфункцией, которая принимает экземпляр сервера Fastify. Это основа плагина Fastify. Оставшийся код в нашем модуле маршрутов будет перемещен внутрь этой функции плагина:

export default async function routes (fastify) {

// Configure routes

}

Чтобы наше промежуточное ПО и маршруты работали с Fastify, нам нужно изменить:

routerссылки наfastify

функции обработчика маршрута должны бытьasync

аргументы функции обработчика маршрута от (request, response, next) до (request, reply)

responseссылки наreply

призывает response.json () кreply.send ()

случаи next (error) _throw error

После внесения всех этих изменений наш модуль маршрутов теперь представляет собой плагин Fastify, содержащий маршруты Fastify:

// src/routes.js

import cors from «cors»;

export default async function routes (fastify) {

fastify.use (cors ({ origin: true }));

fastify.post («/», async function createUser (request, reply) {

const newUser = request.body;

if (! newUser) {

throw new Error («Error creating user») ;

}

reply.status (201).send (newUser) ;

}) ;

fastify.get («/: user_id», async function getUser (request, reply) {

const user = {

id: request.params.user_id,

first_name: «Bobinsky»,

last_name: «Oso»,

};

reply.send (user) ;

}) ;

}

Теперь нам нужно изменить наш модуль приложения (src/app.js), чтобы использовать подключаемый модуль, который мы экспортируем из модуля маршрутов. Это означает замену fastify.use () вызова на вызов fastify.register ():

— fastify.use («/user», routes) ;

+ fastify.register (routes, { prefix: «/user» }) ;

Вы можете просмотреть различия этих изменений кода на GitHub.

Наш пример приложения Express имеет только один маршрутизатор, поэтому мы смогли перенести все маршруты в нашем приложении для использования Fastify за один раз. Однако, если у нас есть более крупное приложение Express с несколькими маршрутизаторами, мы могли бы постепенно перевести каждый маршрутизатор на Fastify по одному.

Замена промежуточного программного обеспечения плагинами

Наше приложение в хорошем состоянии, и мы почти полностью перенесли его с Express на Fastify. Осталось мигрировать: мы используем corsпакет промежуточного программного обеспечения Express. Мы установили fastify-corsплагин ранее, и теперь нам нужно добавить его в наше приложение, чтобы заменить corsпромежуточное ПО.

В нашем модуле маршрутов (src/routes.js) нам нужно заменить importпромежуточное corsПО:

— import cors from «cors»;

+ import CorsPlugin from «fastify-cors»;

Затем нам нужно заменить вызов на fastify.use () вызов fastify.register ():

— fastify.use (cors ({ origin: true }));

+ fastify.register (CorsPlugin, { origin: true }) ;

Обратите внимание, что когда мы регистрируем плагин в Fastify, нам нужно передать функцию плагина и объект параметров в качестве отдельных аргументов.

Поскольку мы больше не используем use () функцию, fastify-expressпредоставляемую плагином, мы можем полностью удалить ее из нашего приложения. Для этого давайте удалим следующие строки из нашего модуля приложения (src/app.js):

— import ExpressPlugin from «fastify-express»;

— await fastify.register (ExpressPlugin) ;

Вы можете просмотреть различия этих изменений кода на GitHub.

Удаление экспресс-зависимостей

Миграция нашего приложения с Express на Fastify завершена! Теперь мы можем удалить зависимости, связанные с Express, выполнив эту команду в нашем терминале:

npm uninstall express cors fastify-express

Вы можете просмотреть различия этих изменений кода на GitHub.

Запуск нашего перенесенного приложения

Теперь, когда мы полностью перенесли наше приложение на Fastify, самое время проверить, все ли работает так, как мы ожидаем. Давайте запустим те же команды, которые мы запускали ранее, когда наше приложение использовало Express.

Сначала мы запустим приложение в нашем терминале:

node src/server.js

Затем в отдельном терминале мы сделаем запрос к API с помощью cURL, чтобы подтвердить, что он работает должным образом:

curl —verbose —request GET \

—url http: //localhost:3000/user/3d395cb4−531c−4989-b8ed-9cc75198187e \

—header 'Origin: http: //example-origin.com’

Мы должны получить ответ, который выглядит следующим образом:

< HTTP/1.1 200 OK

< vary: Origin

< access-control-allow-origin: http://example-origin.com

< content-type: application/json; charset=utf-8

<

{«id»:«3d395cb4−531c−4989-b8ed-9cc75198187e»,«first_name»:«Bobinsky»,«last_name»:"Oso"}

Отказ от ПО промежуточного слоя

В нашем примере приложения Express использовалось всего несколько функций промежуточного программного обеспечения, но наши реальные приложения Express, вероятно, используют гораздо больше. Как мы видели, fastify-expressплагин позволяет нам продолжать использовать промежуточное ПО Express, если нам это нужно. Это позволяет нам отложить переписывание нашего собственного промежуточного программного обеспечения Express в плагины Fastify. Но что мы можем сделать, чтобы заменить стороннее ПО промежуточного слоя Express?

К счастью для нас, для Fastify доступна здоровая экосистема плагинов. Вот некоторые из популярных пакетов промежуточного программного обеспечения Express, которые мы можем заменить плагинами Fastify:

cors ➜ fastify-cors

шлем ➜ fastify-шлем

csurf ➜ fastify-csrf

экспресс-сессияfastify-server-session

экспресс-jwtfastify-jwt

http-ошибкиfastify-sensible

serve-staticfastify-static

мультер ➜ фастфай-мультер

Некоторые из плагинов Fastify являются прямыми портами или оболочками своих аналогов Express. Это означает, что нам часто не нужно будет изменять параметры конфигурации, которые мы передаем плагину Fastify.

Вы можете найти полный список плагинов на странице Fastify Ecosystem.

Максимальное использование Fastify

Теперь, когда мы начали осваивать Fastify, перенеся приложение Express, самое время приступить к рассмотрению других функций Fastify, которые могут нам пригодиться.

Проверка

Fastify предоставляет функции для проверки запросов. Он использует Ajv (другой валидатор схемы JSON) под капотом, что позволяет нам определять правила проверки с помощью схемы JSON.

Вот пример, который использует схему JSON для проверки тела запроса на POSTмаршруте:

const schema = {

body: {

type: «object»,

required: ["first_name"],

properties: {

first_name: { type: «string», minLength: 1 },

},

},

};

app.post («/user», { schema }, async (request, reply) => {

reply.send (request.body) ;

}) ;

Ошибки проверки автоматически форматируются и отправляются в виде ответа JSON:

{

«statusCode»: 400,

«error»: «Bad Request»,

«message»: «body should have required property 'first_name’»

}

Подробнее читайте в документации Fastify Validation and Serialization.

логирование

Вход в приложения Node.js может негативно сказаться на производительности в рабочей среде. Это связано с тем, что существует много шагов, связанных с сериализацией и транспортировкой данных журнала в другое место (например, в Elasticsearch). Важно, чтобы этот аспект наших приложений был хорошо оптимизирован.

Ведение журнала полностью интегрировано в Fastify, а это означает, что нам не нужно тратить время на выбор и интеграцию регистратора. Fastify использует быстрый и гибкий регистратор: pino. Он создает журналы в формате JSON:

{«level»:30,«time»:1615881822269,«pid»:14323,«hostname»:«localhost»,«msg»:«Server listening at http: //127.0.0.1:3000"}

{"level»:30,«time»:1615881829697,«pid»:14323,«hostname»:«localhost»,«reqId»:«req-1»,«req»: {«method»:«GET»,«url»:«/user/abc123»,«hostname»:«localhost:3000»,«remoteAddress»:«127.0.0.1»,«remotePort»:38238},«msg»:«incoming request"}

{"level»:30,«time»:1615881829704,«pid»:14323,«hostname»:«localhost»,«reqId»:«req-1»,«res»: {«statusCode»:200},«responseTime»:6.576989000663161,«msg»:"request completed"}

Когда мы создаем экземпляр сервера Fastify, мы можем включить ведение журнала и настроить параметры, которые передаются в pino. После этого Fastify автоматически выведет сообщения журнала, подобные показанным выше. Экземпляр регистратора доступен в экземпляре сервера Fastify (например, fastify.log.info («...»)) и во всех объектах запроса (например, request.log.info («...»)).

Подробнее читайте в документации Fastify Logging.

Обработка ошибок

Fastify предоставляет метод setErrorHandler (), который позволяет нам явно указать функцию для обработки ошибок. Это отличается от Express, где ПО промежуточного слоя для обработки ошибок можно отличить только по принимаемым параметрам (err, req, res, next), и оно должно добавляться в определенном порядке.

Для полной гибкости мы можем указать разные обработчики ошибок Fastify в разных плагинах. Подробнее читайте в документации Fastify Errors.

Декораторы

Декораторы — это мощная функция Fastify, которая позволяет нам настраивать основные объекты Fastify, такие как наш экземпляр сервера Fastify, а также объекты запросов и ответов. Вот пример базового декоратора:

fastify.register (async (fastify, options) => {

fastify.decorate («yolo», () => {

return { yo: «lo» };

}) ;

fastify.get («/yolo», async function (request, reply) {

// Our Fastify server instance is bound to `this`

reply.send (this.yolo ());

}) ;

}) ;

Декораторы позволяют нам делать такие вещи, как соединения с базами данных или механизмы просмотра, доступными во всем нашем приложении Fastify. Подробнее читайте в документации Fastify Decorators.

Вывод

В этой статье мы узнали, как перенести существующее приложение Node.js с Express на Fastify. Мы видели, как fastify-expressплагин может помочь нам постепенно перенести наши существующие приложения. Это позволяет нам начать пользоваться функциями, которые предоставляет Fastify, даже если некоторые части нашего приложения все еще используют Express.

Вот некоторые ресурсы, которые могут оказаться полезными при переходе с Express на Fastify:

Пример кода из этой статьи. Изучите код и запустите приложения, которые мы создали в этой статье.

Укрепляйте документацию. Полная документация по фреймворку Fastify.

Укрепляйте экосистему. Каталог плагинов для Fastify. Удобно для поиска плагинов для замены промежуточного программного обеспечения Express.

Пример приложения Fastify. Пример приложения, созданного одним из ведущих сопровождающих Fastify. Он демонстрирует основные концепции Fastify, лучшие практики и рекомендации.

Fastify сообщество Discord сервер. Отличное место, где можно получить помощь и совет по разработке приложений с помощью Fastify.

3D-печать5GABC-анализAndroidAppleAppStoreAsusCall-центрChatGPTCRMDellDNSDrupalExcelFacebookFMCGGoogleHuaweiInstagramiPhoneLinkedInLinuxMagentoMicrosoftNvidiaOpenCartPlayStationPOS материалPPC-специалистRuTubeSamsungSEO-услугиSMMSnapchatSonyStarlinkTikTokTwitterUbuntuUp-saleViasatVPNWhatsAppWindowsWordPressXiaomiYouTubeZoomАвдеевкаАктивные продажиАкцияАлександровск ЛНРАлмазнаяАлчевскАмвросиевкаАнализ конкурентовАнализ продажАнтимерчандайзингАнтрацитАртемовскАртемовск ЛНРАссортиментная политикаБелгородБелицкоеБелозерскоеБердянскБизнес-идеи (стартапы)БрендБрянкаБукингВахрушевоВендорВидеоВикипедияВирусная рекламаВирусный маркетингВладивостокВнутренние продажиВнутренний маркетингВолгоградВолновахаВоронежГорловкаГорнякГорскоеДебальцевоДебиторкаДебиторская задолженностьДезинтермедитацияДзержинскДивизионная система управленияДизайнДимитровДирект-маркетингДисконтДистрибьюторДистрибьюцияДобропольеДокучаевскДоменДружковкаЕкатеринбургЕнакиевоЖдановкаЗапорожьеЗимогорьеЗолотоеЗоринскЗугрэсИжевскИловайскИрминоКазаньКалининградКировскКировскоеКомсомольскоеКонстантиновкаКонтент-маркетингКонтент-планКопирайтингКраматорскКрасноармейскКрасногоровкаКраснодарКраснодонКраснопартизанскКрасный ЛиманКрасный ЛучКременнаяКураховоКурскЛисичанскЛуганскЛутугиноМакеевкаМариупольМаркетингМаркетинговая информацияМаркетинговые исследованияМаркетинговый каналМаркетинг услугМаркетологМарьинкаМедиаМелекиноМелитопольМенеджментМерчандайзерМерчандайзингМиусинскМолодогвардейскМоскваМоспиноНижний НовгородНиколаевНиколаевкаНишевой маркетингНовоазовскНовогродовкаНоводружескНовосибирскНумерическая дистрибьюцияОдессаОмскОтдел маркетингаПартизанский маркетингПервомайскПеревальскПетровскоеПлата за кликПоисковая оптимизацияПопаснаяПравило ПаретоПривольеПрогнозирование продажПродвижение сайтов в ДонецкеПроизводство видеоПромоПромоушнПрямой маркетингРабота для маркетологаРабота для студентаРазработка приложенийРаспродажаРегиональные продажиРекламаРеклама на асфальтеРемаркетингРетро-бонусРибейтРитейлРовенькиРодинскоеРостов-на-ДонуРубежноеСамараСанкт-ПетербургСаратовСватовоСвердловскСветлодарскСвятогорскСевастопольСеверодонецкСеверскСедовоСейлз промоушнСелидовоСимферопольСинергияСколковоСлавянскСнежноеСоздание сайтов в ДонецкеСоледарСоциальные сетиСочиСтаробельскСтаробешевоСтахановСтимулирование сбытаСуходольскСчастьеТелемаркетингТельмановоТираспольТорговый представительТорезТрейд маркетингТрейд промоушнТюменьУглегорскУгледарУкраинскХабаровскХарцызскХерсонХостингЦелевая аудиторияЦифровой маркетингЧасов ЯрЧелябинскШахтерскЮжно-СахалинскЮнокоммунаровскЯндексЯсиноватая