{"id":344376,"date":"2023-01-24T09:01:54","date_gmt":"2023-01-24T09:01:54","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=344376"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=344376","title":{"rendered":"<span>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Next.js \u0438 TypeScript. \u0427\u0430\u0441\u0442\u044c 1. \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/by\/f9\/qu\/byf9qu-qkjvc3cpega2osikmrcq.png\" data-src=\"https:\/\/habrastorage.org\/webt\/by\/f9\/qu\/byf9qu-qkjvc3cpega2osikmrcq.png\"\/>  <\/p>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0442, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p>  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0438\u0437 2 \u0441\u0442\u0430\u0442\u0435\u0439-\u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u043e\u0432 \u043c\u044b \u0441 \u0432\u0430\u043c\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0435 (\u0444\u0443\u043b\u043b\u0441\u0442\u0435\u043a \u2014 fullstack) \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/nextjs.org\/\">Next.js<\/a> \u0438 <a href=\"https:\/\/www.typescriptlang.org\/\">TypeScript<\/a>.<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/my-js.org\/docs\/guide\/nextjs\">\u0420\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e Next.js<\/a>.<\/li>\n<li><a href=\"https:\/\/my-js.org\/docs\/guide\/ts\">\u041a\u0430\u0440\u043c\u0430\u043d\u043d\u0430\u044f \u043a\u043d\u0438\u0433\u0430 \u043f\u043e TypeScript<\/a>.<\/li>\n<\/ul>\n<p>  <\/p>\n<ol>\n<li>\u041d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0431\u043e\u0439 \u0431\u043b\u043e\u0433 \u2014 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438, \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u043e\u0432.<\/li>\n<li>\u041c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <a href=\"https:\/\/jwt.io\/\">JSON Web Tokens<\/a> \u0438 <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Cookies\">HTTP-\u043a\u0443\u043a\u0438<\/a>.<\/li>\n<li>\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u043f\u043e\u0441\u0442\u043e\u0432 \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0432 \u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 <a href=\"https:\/\/www.sqlite.org\/\">SQLite<\/a>.<\/li>\n<\/ol>\n<p>  <\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u043e\u043c \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0435 \u043c\u044b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0440\u043e\u0443\u0442\u043e\u0432 (API Routes), \u0432\u043e \u0432\u0442\u043e\u0440\u043e\u043c \u2014 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u0434\u0430\u043d\u043d\u044b\u0439 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d \u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043c\u0435\u044e\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u044b\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 <a href=\"https:\/\/ru.reactjs.org\/\">React<\/a> \u0438 <a href=\"https:\/\/nodejs.org\/\">Node.js<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0442\u0435\u0445, \u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0434, \u0432\u043e\u0442 <a href=\"https:\/\/github.com\/harryheman\/Blog-Posts\/tree\/master\/fullstack-next-ts-app\">\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e? \u0422\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.<a name=\"habracut\"><\/a><\/p>\n<p>  <\/p>\n<h2 id=\"podgotovka-i-nastroyka-proekta\">\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>  <\/p>\n<h3 id=\"sozdanie-proekta-i-ustanovka-zavisimostey\">\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439<\/h3>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f <a href=\"https:\/\/yarnpkg.com\/\">Yarn<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 Next.js-\u043f\u0440\u043e\u0435\u043a\u0442 \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 TS \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/nextjs.org\/docs\/api-reference\/create-next-app\">Create Next App<\/a>:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">yarn create next-app fullstack-next-ts-app --ts<\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/rl\/9o\/ni\/rl9oni2indqo888lavzejtxdc2a.png\" data-src=\"https:\/\/habrastorage.org\/webt\/rl\/9o\/ni\/rl9oni2indqo888lavzejtxdc2a.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p><em>\u0421\u043e\u0432\u0435\u0442\u0443\u044e \u0432\u0437\u0433\u043b\u044f\u043d\u0443\u0442\u044c \u043d\u0430 <a href=\"https:\/\/tabby.sh\/\">Tabby<\/a> \u2014 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0441 \u043a\u0443\u0447\u0435\u0439 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439<\/em><\/p>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>, \u0447\u0442\u043e \u043c\u044b \u0432\u044b\u0431\u0440\u0430\u043b\u0438 <a href=\"https:\/\/eslint.org\/\">ESLint<\/a> \u0438 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>src<\/code> \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u043e\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u043e \u043e\u0442\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u043e\u0442 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>app<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 npm-\u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\"># \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 yarn add @emotion\/cache @emotion\/react @emotion\/server @emotion\/styled @formkit\/auto-animate @mui\/icons-material @mui\/joy @mui\/material @prisma\/client @welldone-software\/why-did-you-render argon2 cookie jsonwebtoken multer next-connect react-error-boundary react-toastify swiper swr # \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 yarn add -D @types\/cookie @types\/jsonwebtoken @types\/multer babel-plugin-import prisma sass<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li><code>@mui\/...<\/code> \u2014 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438 \u0438\u043a\u043e\u043d\u043a\u0438 <a href=\"https:\/\/mui.com\/\">Material UI<\/a>;<\/li>\n<li><code>@emotion\/...<\/code> \u2014 <a href=\"https:\/\/emotion.sh\/docs\/introduction\">\u0440\u0435\u0448\u0435\u043d\u0438\u0435 CSS-\u0432-JS<\/a>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 Material UI;<\/li>\n<li><a href=\"https:\/\/www.prisma.io\/\">prisma<\/a> \u2014 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/ORM\">ORM<\/a> \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u044b\u043c\u0438 \u0411\u0414 PostgreSQL, MySQL, SQLite \u0438 SQL Server, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441 NoSQL-\u0411\u0414 MongoDB \u0438 CockroachDB;<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/@prisma\/client\">@prisma\/client<\/a> \u2014 \u043a\u043b\u0438\u0435\u043d\u0442 Prisma;<\/li>\n<li><a href=\"https:\/\/github.com\/welldone-software\/why-did-you-render\">@welldone-software\/why-did-you-render<\/a> \u2014 \u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438 React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0430\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u0440\u0438\u0447\u0438\u043d\u0443 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430;<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/argon2\">argon2<\/a> \u2014 \u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u0430\u0440\u043e\u043b\u0435\u0439;<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/cookie\">cookie<\/a> \u2014 \u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u0443\u043a\u0438;<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/jsonwebtoken\">jsonwebtoken<\/a> \u2014 \u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0442\u043e\u043a\u0435\u043d\u0430\u043c\u0438;<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/multer\">multer<\/a> \u2014 \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a (middleware) Node.js \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 <code>multipart\/form-data<\/code> (\u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u043c\u0438\u0441\u044f \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435);<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/next-connect\">next-connect<\/a> \u2014 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u0440\u043e\u0443\u0442\u043e\u0432 Next.js \u043a\u0430\u043a \u0441 \u0440\u043e\u0443\u0442\u0430\u043c\u0438 <a href=\"https:\/\/expressjs.com\/ru\/\">Express<\/a>;<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/react-error-boundary\">react-error-boundary<\/a> \u2014 <a href=\"https:\/\/reactjs.org\/docs\/error-boundaries.html\">\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442-\u043f\u0440\u0435\u0434\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u0435\u043b\u044c<\/a> \u0434\u043b\u044f React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439;<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/react-toastify\">react-toastify<\/a> \u2014 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0438 \u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0432 React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445;<\/li>\n<li><a href=\"https:\/\/swiperjs.com\/\">swiper<\/a> \u2014 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441\u043b\u0430\u0439\u0434\u0435\u0440\u0430;<\/li>\n<li><a href=\"https:\/\/swr.vercel.app\/\">swr<\/a> \u2014 \u0445\u0443\u043a\u0438 React \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u2014 fetching) \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0435 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0431\u0435\u0437 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c (state manager);<\/li>\n<li><code>@types\/...<\/code> \u2014 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u044e\u0449\u0438\u0435 \u0442\u0438\u043f\u044b TS;<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/babel-plugin-import\">babel-plugin-import<\/a> \u2014 \u043f\u043b\u0430\u0433\u0438\u043d <a href=\"https:\/\/babeljs.io\/\">Babel<\/a> \u0434\u043b\u044f \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439 &#171;\u0442\u0440\u044f\u0441\u043a\u0438 \u0434\u0435\u0440\u0435\u0432\u0430&#187; (tree shaking) \u043f\u0440\u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 MUI \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e;<\/li>\n<li><a href=\"https:\/\/sass-lang.com\/\">sass<\/a> \u2014 \u043f\u0440\u0435\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 CSS.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u044d\u0442\u0438\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0434\u0430\u043b\u0435\u0435 \u0438 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430.<\/p>\n<p>  <\/p>\n<h3 id=\"podgotovka-bd-i-nastroyka-orm\">\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0411\u0414 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 ORM<\/h3>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u043f\u043e\u0441\u0442\u043e\u0432 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u0430 \u0411\u0414. \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c SQLite \u2014 \u0432 \u044d\u0442\u043e\u0439 \u0411\u0414 \u0434\u0430\u043d\u043d\u044b\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 \u0444\u0430\u0439\u043b\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 SQLite \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f Prisma.<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/my-js.org\/docs\/guide\/prisma\">\u0420\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e Prisma<\/a>.<\/li>\n<\/ul>\n<p>  <\/p>\n<p><em>\u0421\u043e\u0432\u0435\u0442\u0443\u044e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=Prisma.prisma\">\u044d\u0442\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f VSCode<\/a> \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0441\u0445\u0435\u043c\u043e\u0439 Prisma<\/em><\/p>\n<p>  <\/p>\n<p>\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c Prisma, \u043d\u0430\u0445\u043e\u0434\u044f\u0441\u044c \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">npx prisma init<\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/x2\/7m\/yc\/x27mycjja10txzjvpn4c2cwaqty.png\" data-src=\"https:\/\/habrastorage.org\/webt\/x2\/7m\/yc\/x27mycjja10txzjvpn4c2cwaqty.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>prisma<\/code> \u0438 \u0444\u0430\u0439\u043b\u0430 <code>.env<\/code>. \u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b <code>schema.prisma<\/code> \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>prisma<\/code>, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044f \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 \u0434\u043b\u044f \u0411\u0414 \u0432 \u0431\u043b\u043e\u043a\u0435 <code>datasource<\/code> \u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043f\u043e\u0441\u0442\u0430 \u0438 \u043b\u0430\u0439\u043a\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">generator client {   provider = \"prisma-client-js\" }  datasource db {   \/\/ !   provider = \"sqlite\"   url      = env(\"DATABASE_URL\") }  \/\/ \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f model User {   id        String  @id @default(uuid())   username  String?   avatarUrl String?   email     String  @unique   password  String   posts     Post[]   likes     Like[] } \/\/ \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u0441\u0442\u0430 model Post {   id        String   @id @default(uuid())   title     String   content   String   author    User     @relation(fields: [authorId], references: [id], onUpdate: Cascade, onDelete: Cascade)   authorId  String   likes     Like[]   createdAt DateTime @default(now())   updatedAt DateTime @updatedAt } \/\/ \u043c\u043e\u0434\u0435\u043b\u044c \u043b\u0430\u0439\u043a\u0430 model Like {   id     String @id @default(uuid())   user   User   @relation(fields: [userId], references: [id])   userId String   post   Post   @relation(fields: [postId], references: [id], onUpdate: Cascade, onDelete: Cascade)   postId String }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b <code>.env<\/code>, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044f \u0432 \u043d\u0435\u043c \u043f\u0443\u0442\u044c \u043a \u0444\u0430\u0439\u043b\u0443 \u0411\u0414:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">DATABASE_URL=\"file:.\/dev.db\"<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e \u043a \u0411\u0414:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">npx prisma migrate dev --name init<\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/un\/am\/m4\/unamm4qyvayu8ivnku-z-znm44i.png\" data-src=\"https:\/\/habrastorage.org\/webt\/un\/am\/m4\/unamm4qyvayu8ivnku-z-znm44i.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>migrations<\/code> \u0441 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0435\u0439 \u043d\u0430 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/SQL\">SQL<\/a>.<\/p>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 <code>migrate dev<\/code> \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u043b\u0438\u0435\u043d\u0442 Prisma. \u0412 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043f\u0440\u0438 \u043b\u044e\u0431\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0441\u0445\u0435\u043c\u044b Prisma \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <code>npx prisma generate<\/code> \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 <em>\u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>, \u0447\u0442\u043e \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0411\u0414 \u0441 \u043f\u043e\u0442\u0435\u0440\u0435\u0439 \u0432\u0441\u0435\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0444\u0430\u0439\u043b <code>dev.db<\/code> \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <code>npx prisma db push<\/code>.<\/p>\n<p>  <\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0430 Prisma. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b <code>src\/utils\/prisma.ts<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ https:\/\/github.com\/prisma\/prisma-examples\/blob\/latest\/typescript\/rest-nextjs-api-routes-auth\/lib\/prisma.ts import { PrismaClient } from '@prisma\/client' declare let global: { prisma: PrismaClient }  let prisma: PrismaClient  if (process.env.NODE_ENV === 'production') {   prisma = new PrismaClient() } else {   if (!global.prisma) {     global.prisma = new PrismaClient()   }   prisma = global.prisma }  export default prisma<\/code><\/pre>\n<p>  <\/p>\n<p>\u042d\u0442\u043e\u0442 \u0441\u043d\u0438\u043f\u043f\u0435\u0442 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u043e\u0433\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 (\u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d\u0430 \u2014 singleton) \u043a\u043b\u0438\u0435\u043d\u0442\u0430 Prisma \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u043a\u0430\u043a \u0432 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0441\u0440\u0435\u0434\u0435, \u0442\u0430\u043a \u0438 \u0432 \u0441\u0440\u0435\u0434\u0435 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0414\u0435\u043b\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438\u0437-\u0437\u0430 <a href=\"https:\/\/webpack.js.org\/concepts\/hot-module-replacement\/\">HMR<\/a> \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u043c\u043e\u0434\u0443\u043b\u044f, \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0433\u043e <code>prisma<\/code>, \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<p>  <\/p>\n<h3 id=\"podgotovka-i-nastroyka-staticheskih-dannyh-dlya-klienta\">\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/h3>\n<p>  <\/p>\n<p>\u041d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u0438\u0437 3 \u0441\u0442\u0440\u0430\u043d\u0438\u0446: \u0433\u043b\u0430\u0432\u043d\u043e\u0439, \u0431\u043b\u043e\u0433\u0430 \u0438 \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u043e\u0432. \u041d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u043e\u0432 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e, \u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u043e\u0432 \u2014 \u0432 <a href=\"https:\/\/jsonbin.io\/\">JSONBin<\/a>. \u0414\u043b\u044f \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <a href=\"https:\/\/nextjs.org\/docs\/basic-features\/data-fetching\/get-static-props\">getStaticProps<\/a>, \u0430 \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u043e\u0432 \u2014 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0441 \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0435\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0435\u0439 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0439 getStaticProps \u0438 <a href=\"https:\/\/nextjs.org\/docs\/basic-features\/data-fetching\/get-static-paths\">getStaticPaths<\/a>. \u041c\u044b \u0435\u0449\u0435 \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e\u0431 \u044d\u0442\u043e\u043c \u0432\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430.<\/p>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b <code>public\/data\/home.json<\/code> \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b:<\/p>\n<p>  <\/p>\n<pre><code class=\"json\">{   \"blocks\": [     {       \"id\": 1,       \"imgSrc\": \"\/img\/landscape.jpg\",       \"imgAlt\": \"First landscape\",       \"title\": \"First block\",       \"description\": \"Lorem ipsum dolor sit amet consectetur adipisicing elit. Magni amet illum recusandae numquam iste repudiandae inventore. Sit quis, impedit autem dolorum, perspiciatis tempora voluptas consectetur expedita aspernatur reiciendis labore recusandae voluptatibus, explicabo laboriosam ut temporibus doloremque! Voluptate recusandae commodi quis dolor adipisci fugiat earum? Ratione aliquam modi deserunt voluptatibus error.\"     },     {       \"id\": 2,       \"imgSrc\": \"\/img\/landscape2.jpg\",       \"imgAlt\": \"Second landscape\",       \"title\": \"Second block\",       \"description\": \"Lorem ipsum dolor sit amet consectetur adipisicing elit. Magni amet illum recusandae numquam iste repudiandae inventore. Sit quis, impedit autem dolorum, perspiciatis tempora voluptas consectetur expedita aspernatur reiciendis labore recusandae voluptatibus, explicabo laboriosam ut temporibus doloremque! Voluptate recusandae commodi quis dolor adipisci fugiat earum? Ratione aliquam modi deserunt voluptatibus error.\"     },     {       \"id\": 3,       \"imgSrc\": \"https:\/\/images.unsplash.com\/photo-1506744038136-46273834b3fb?ixlib=rb-4.0.3&amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;auto=format&amp;fit=crop&amp;w=1170&amp;q=80\",       \"imgAlt\": \"Third landscape\",       \"title\": \"Third block\",       \"description\": \"Lorem ipsum dolor sit amet consectetur adipisicing elit. Magni amet illum recusandae numquam iste repudiandae inventore. Sit quis, impedit autem dolorum, perspiciatis tempora voluptas consectetur expedita aspernatur reiciendis labore recusandae voluptatibus, explicabo laboriosam ut temporibus doloremque! Voluptate recusandae commodi quis dolor adipisci fugiat earum? Ratione aliquam modi deserunt voluptatibus error.\"     },     {       \"id\": 4,       \"imgSrc\": \"https:\/\/images.unsplash.com\/photo-1434725039720-aaad6dd32dfe?ixlib=rb-4.0.3&amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;auto=format&amp;fit=crop&amp;w=1042&amp;q=80\",       \"imgAlt\": \"Forth landscape\",       \"title\": \"Forth block\",       \"description\": \"Lorem ipsum dolor sit amet consectetur adipisicing elit. Magni amet illum recusandae numquam iste repudiandae inventore. Sit quis, impedit autem dolorum, perspiciatis tempora voluptas consectetur expedita aspernatur reiciendis labore recusandae voluptatibus, explicabo laboriosam ut temporibus doloremque! Voluptate recusandae commodi quis dolor adipisci fugiat earum? Ratione aliquam modi deserunt voluptatibus error.\"     }   ] }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u0421\u043e\u0432\u0435\u0442\u0443\u044e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=AykutSarac.jsoncrack-vscode\">\u044d\u0442\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f VSCode<\/a> \u0434\u043b\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON<\/em><\/p>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em> \u043d\u0430 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439 (<code>imgSrc<\/code>). 2 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>public\/img<\/code>, \u0430 \u0435\u0449\u0435 2 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0441 <a href=\"https:\/\/unsplash.com\/\">Unsplash<\/a>. \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 (origin) \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0444\u0430\u0439\u043b <code>next.config.js<\/code> \u0442\u0430\u043a\u0443\u044e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">images: {   domains: ['images.unsplash.com'] }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0443\u0435\u043c\u0441\u044f \u0432 JSONBin, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b &#171;Bins&#187;, \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u043c &#171;Create a Bin&#187; \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u043e\u0432 (\u043d\u043e\u0432\u043e\u0441\u0442\u0438 \u2014 \u0444\u0430\u0439\u043b <code>public\/data\/news.json<\/code>):<\/p>\n<p>  <\/p>\n<pre><code class=\"json\">{   \"news\": [     {       \"id\": 1,       \"imgSrc\": \"https:\/\/images.unsplash.com\/photo-1506744038136-46273834b3fb?ixlib=rb-4.0.3&amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;auto=format&amp;fit=crop&amp;w=1170&amp;q=80\",       \"imgAlt\": \"First landscape\",       \"author\": \"John\",       \"datePublished\": \"2022\/12\/31\",       \"title\": \"First news\",       \"description\": \"Lorem, ipsum dolor sit amet consectetur adipisicing elit. Blanditiis vel, odio perspiciatis alias quos et labore sit ab laborum. Laboriosam hic autem earum tempore voluptas?\",       \"text\": \"Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos recusandae aspernatur, distinctio autem quia dolor sed libero dignissimos suscipit. Earum aliquam eius eaque corporis cupiditate velit, odit ullam officia nam quibusdam ex laborum possimus eveniet aliquid adipisci assumenda necessitatibus ducimus. Enim nesciunt fuga, aperiam deserunt quia, aut itaque omnis similique molestias veniam assumenda repellendus consequuntur error exercitationem ex debitis quod quidem magni. Cupiditate iure corporis veritatis tenetur rerum, animi quisquam praesentium accusantium est quas in! Eligendi vitae corrupti sunt distinctio nisi blanditiis atque reprehenderit incidunt obcaecati corporis laborum voluptate iusto nostrum dolorum temporibus facere inventore, quaerat optio unde consequuntur velit.\"     },     {       \"id\": 2,       \"imgSrc\": \"https:\/\/images.unsplash.com\/photo-1494500764479-0c8f2919a3d8?ixlib=rb-4.0.3&amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;auto=format&amp;fit=crop&amp;w=1170&amp;q=80\",       \"imgAlt\": \"Second landscape\",       \"author\": \"Jane\",       \"datePublished\": \"2022\/12\/31\",       \"title\": \"Second news\",       \"description\": \"Lorem, ipsum dolor sit amet consectetur adipisicing elit. Blanditiis vel, odio perspiciatis alias quos et labore sit ab laborum. Laboriosam hic autem earum tempore voluptas?\",       \"text\": \"Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos recusandae aspernatur, distinctio autem quia dolor sed libero dignissimos suscipit. Earum aliquam eius eaque corporis cupiditate velit, odit ullam officia nam quibusdam ex laborum possimus eveniet aliquid adipisci assumenda necessitatibus ducimus. Enim nesciunt fuga, aperiam deserunt quia, aut itaque omnis similique molestias veniam assumenda repellendus consequuntur error exercitationem ex debitis quod quidem magni. Cupiditate iure corporis veritatis tenetur rerum, animi quisquam praesentium accusantium est quas in! Eligendi vitae corrupti sunt distinctio nisi blanditiis atque reprehenderit incidunt obcaecati corporis laborum voluptate iusto nostrum dolorum temporibus facere inventore, quaerat optio unde consequuntur velit.\"     },     {       \"id\": 3,       \"imgSrc\": \"https:\/\/images.unsplash.com\/photo-1506744038136-46273834b3fb?ixlib=rb-4.0.3&amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;auto=format&amp;fit=crop&amp;w=1170&amp;q=80\",       \"imgAlt\": \"Third landscape\",       \"author\": \"Bob\",       \"datePublished\": \"2022\/12\/31\",       \"title\": \"Third news\",       \"description\": \"Lorem, ipsum dolor sit amet consectetur adipisicing elit. Blanditiis vel, odio perspiciatis alias quos et labore sit ab laborum. Laboriosam hic autem earum tempore voluptas?\",       \"text\": \"Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos recusandae aspernatur, distinctio autem quia dolor sed libero dignissimos suscipit. Earum aliquam eius eaque corporis cupiditate velit, odit ullam officia nam quibusdam ex laborum possimus eveniet aliquid adipisci assumenda necessitatibus ducimus. Enim nesciunt fuga, aperiam deserunt quia, aut itaque omnis similique molestias veniam assumenda repellendus consequuntur error exercitationem ex debitis quod quidem magni. Cupiditate iure corporis veritatis tenetur rerum, animi quisquam praesentium accusantium est quas in! Eligendi vitae corrupti sunt distinctio nisi blanditiis atque reprehenderit incidunt obcaecati corporis laborum voluptate iusto nostrum dolorum temporibus facere inventore, quaerat optio unde consequuntur velit.\"     },     {       \"id\": 4,       \"imgSrc\": \"https:\/\/images.unsplash.com\/photo-1434725039720-aaad6dd32dfe?ixlib=rb-4.0.3&amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;auto=format&amp;fit=crop&amp;w=1042&amp;q=80\",       \"imgAlt\": \"Forth landscape\",       \"author\": \"Alice\",       \"datePublished\": \"2022\/12\/31\",       \"title\": \"Forth news\",       \"description\": \"Lorem, ipsum dolor sit amet consectetur adipisicing elit. Blanditiis vel, odio perspiciatis alias quos et labore sit ab laborum. Laboriosam hic autem earum tempore voluptas?\",       \"text\": \"Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos recusandae aspernatur, distinctio autem quia dolor sed libero dignissimos suscipit. Earum aliquam eius eaque corporis cupiditate velit, odit ullam officia nam quibusdam ex laborum possimus eveniet aliquid adipisci assumenda necessitatibus ducimus. Enim nesciunt fuga, aperiam deserunt quia, aut itaque omnis similique molestias veniam assumenda repellendus consequuntur error exercitationem ex debitis quod quidem magni. Cupiditate iure corporis veritatis tenetur rerum, animi quisquam praesentium accusantium est quas in! Eligendi vitae corrupti sunt distinctio nisi blanditiis atque reprehenderit incidunt obcaecati corporis laborum voluptate iusto nostrum dolorum temporibus facere inventore, quaerat optio unde consequuntur velit.\"     },     {       \"id\": 5,       \"imgSrc\": \"https:\/\/images.unsplash.com\/34\/BA1yLjNnQCI1yisIZGEi_2013-07-16_1922_IMG_9873.jpg?ixlib=rb-4.0.3&amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;auto=format&amp;fit=crop&amp;w=1171&amp;q=80\",       \"imgAlt\": \"Fifth landscape\",       \"author\": \"Alice\",       \"datePublished\": \"2022\/12\/31\",       \"title\": \"Fifth news\",       \"description\": \"Lorem, ipsum dolor sit amet consectetur adipisicing elit. Blanditiis vel, odio perspiciatis alias quos et labore sit ab laborum. Laboriosam hic autem earum tempore voluptas?\",       \"text\": \"Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos recusandae aspernatur, distinctio autem quia dolor sed libero dignissimos suscipit. Earum aliquam eius eaque corporis cupiditate velit, odit ullam officia nam quibusdam ex laborum possimus eveniet aliquid adipisci assumenda necessitatibus ducimus. Enim nesciunt fuga, aperiam deserunt quia, aut itaque omnis similique molestias veniam assumenda repellendus consequuntur error exercitationem ex debitis quod quidem magni. Cupiditate iure corporis veritatis tenetur rerum, animi quisquam praesentium accusantium est quas in! Eligendi vitae corrupti sunt distinctio nisi blanditiis atque reprehenderit incidunt obcaecati corporis laborum voluptate iusto nostrum dolorum temporibus facere inventore, quaerat optio unde consequuntur velit.\"     },     {       \"id\": 6,       \"imgSrc\": \"https:\/\/images.unsplash.com\/photo-1429704658776-3d38c9990511?ixlib=rb-4.0.3&amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;auto=format&amp;fit=crop&amp;w=1079&amp;q=80\",       \"imgAlt\": \"Sixth landscape\",       \"author\": \"Bob\",       \"datePublished\": \"2022\/12\/31\",       \"title\": \"Sixth news\",       \"description\": \"Lorem, ipsum dolor sit amet consectetur adipisicing elit. Blanditiis vel, odio perspiciatis alias quos et labore sit ab laborum. Laboriosam hic autem earum tempore voluptas?\",       \"text\": \"Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos recusandae aspernatur, distinctio autem quia dolor sed libero dignissimos suscipit. Earum aliquam eius eaque corporis cupiditate velit, odit ullam officia nam quibusdam ex laborum possimus eveniet aliquid adipisci assumenda necessitatibus ducimus. Enim nesciunt fuga, aperiam deserunt quia, aut itaque omnis similique molestias veniam assumenda repellendus consequuntur error exercitationem ex debitis quod quidem magni. Cupiditate iure corporis veritatis tenetur rerum, animi quisquam praesentium accusantium est quas in! Eligendi vitae corrupti sunt distinctio nisi blanditiis atque reprehenderit incidunt obcaecati corporis laborum voluptate iusto nostrum dolorum temporibus facere inventore, quaerat optio unde consequuntur velit.\"     }   ] }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0430\u0436\u0438\u043c\u0430\u0435\u043c \u043d\u0430 \u0448\u0435\u0441\u0442\u0435\u0440\u0435\u043d\u043a\u0443 \u0438 \u0432\u0432\u043e\u0434\u0438\u043c <code>news<\/code> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0431\u0438\u043d\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u043c \u043d\u0430 \u0437\u0430\u043c\u043e\u0447\u0435\u043a \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0431\u0438\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/ka\/4r\/nm\/ka4rnmc4b0qpbn9couzhzrafswa.png\" data-src=\"https:\/\/habrastorage.org\/webt\/ka\/4r\/nm\/ka4rnmc4b0qpbn9couzhzrafswa.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>\u041d\u0430\u0436\u0438\u043c\u0430\u0435\u043c &#171;Save Bin&#187; \u0438 \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c BIN ID \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>JSONBIN_BIN_ID<\/code> \u0432 \u0444\u0430\u0439\u043b\u0435 <code>.env<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">JSONBIN_BIN_ID=&lt;\u0432\u0430\u0448-bin-id><\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b &#171;API KEYS&#187;, \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u043c &#171;Create Access Key&#187;, \u0432\u0432\u043e\u0434\u0438\u043c <code>news<\/code> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043a\u043b\u044e\u0447\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c &#171;Read&#187; \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 &#171;Bins&#187;:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/0x\/uc\/9d\/0xuc9dvdhn6erolejz1dxgsaqgc.png\" data-src=\"https:\/\/habrastorage.org\/webt\/0x\/uc\/9d\/0xuc9dvdhn6erolejz1dxgsaqgc.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>\u041d\u0430\u0436\u0438\u043c\u0430\u0435\u043c &#171;Save Access Key&#187; \u0438 \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0435\u0439 &#171;X-MASTER-KEY&#187; \u0438 &#171;X-ACCESS_KEY&#187; \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">JSONBIN_X_MASTER_KEY=&lt;x-master-key> JSONBIN_X_ACCESS_KEY=&lt;x-access-key><\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b <code>environment.d.ts<\/code> \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0432 \u043d\u0435\u043c \u0442\u0438\u043f\u044b \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0441\u0440\u0435\u0434\u044b \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">declare namespace NodeJS {   interface ProcessEnv {     JSONBIN_BIN_ID: string     JSONBIN_X_MASTER_KEY: string     JSONBIN_X_ACCESS_KEY: string     \/\/ \u043e\u0431 \u044d\u0442\u043e\u043c \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435     ID_TOKEN_SECRET: string     ACCESS_TOKEN_PAYLOAD: string     ACCESS_TOKEN_SECRET: string     COOKIE_NAME: string   } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0432 <code>tsconfig.json<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"json\">\"include\": [   \"next-env.d.ts\",   \"environment.d.ts\",   \"**\/*.ts\",   \"**\/*.tsx\", ],<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u0436\u0430\u043b\u0443\u0439, \u044d\u0442\u043e \u0432\u0441\u0435, \u0447\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435.<\/p>\n<p>  <\/p>\n<h2 id=\"autentifikaciya-i-avtorizaciya\">\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f<\/h2>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0438 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0445 \u0441\u0445\u0435\u043c \u2014 JSON Web Tokens + Cookie. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0432\u044b\u0441\u043e\u043a\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435 \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 (<code>idToken<\/code>) \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0433\u043e ID) \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 \u043a\u0443\u043a\u0438 \u0441\u043e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438;<\/li>\n<li>\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u0443\u043a\u0438 \u0438\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438. \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d, \u0441\u0435\u0440\u0432\u0435\u0440 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 ID \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u0442\u043e\u043a\u0435\u043d\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u0411\u0414 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0438\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u0443;<\/li>\n<li>\u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c \u0441\u0435\u0440\u0432\u0435\u0440 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430 (<code>accessToken<\/code>) \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0435\u0433\u043e \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u043c\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u0443;<\/li>\n<li>\u043f\u0440\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0435 \u043a \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u043e\u043c\u0443 \u0440\u0435\u0441\u0443\u0440\u0441\u0443 \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0438 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0438\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 <code>Authorization<\/code> \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/li>\n<\/ul>\n<p>  <\/p>\n<h3 id=\"posredniki-i-utility-avtorizacii\">\u041f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a\u0438 \u0438 \u0443\u0442\u0438\u043b\u0438\u0442\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/h3>\n<p>  <\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c 2 \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a\u0430 \u0438 1 \u0443\u0442\u0438\u043b\u0438\u0442\u0443 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>cookie<\/code> \u2014 \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u0443\u043a\u0438;<\/li>\n<li><code>authGuard<\/code> \u2014 \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c;<\/li>\n<li><code>checkFields<\/code> \u2014 \u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u0432 \u0442\u0435\u043b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043a\u0443\u043a\u0438 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>.env<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">ID_TOKEN_SECRET=\"id-token-secret\" ACCESS_TOKEN_PAYLOAD=\"access-token-payload\" ACCESS_TOKEN_SECRET=\"access-token-secret\" COOKIE_NAME=\"uid\"<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0441\u0435\u043a\u0440\u0435\u0442\u044b \u0438 \u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0434\u043b\u0438\u043d\u043d\u044b\u043c\u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438 \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438.<\/p>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0442\u0438\u043f\u044b \u0434\u043b\u044f \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a\u0430 <code>cookie<\/code> \u0432 \u0444\u0430\u0439\u043b\u0435 <code>src\/types.ts<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { CookieSerializeOptions } from 'cookie' import { NextApiRequest, NextApiResponse } from 'next'  \/\/ \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 export type CookieArgs = {   name: string   value: any   options?: CookieSerializeOptions }  \/\/ \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u043e\u0442\u0432\u0435\u0442\u0430 export type NextApiResponseWithCookie = NextApiResponse &amp; {   cookie: (args: CookieArgs) => void }  \/\/ \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 export type NextApiHandlerWithCookie = (   req: NextApiRequest,   res: NextApiResponseWithCookie ) => unknown | Promise&lt;unknown>  \/\/ \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0442\u0438\u043f \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a\u0430 export type NextApiMiddleware&lt;H, R> = (   handler: H ) => (req: NextApiRequest, res: R) => void<\/code><\/pre>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u0443\u043a\u0438 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>utils\/cookie.ts<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { serialize } from 'cookie' import { NextApiResponse } from 'next' import {   CookieArgs,   NextApiHandlerWithCookie,   NextApiMiddleware,   NextApiResponseWithCookie } from '..\/types'  const cookieFn = (   res: NextApiResponse,   { name, value, options = {} }: CookieArgs ) => {   const stringValue =     typeof value === 'object' ? 'j:' + JSON.stringify(value) : String(value)    if (typeof options.maxAge === 'number') {     options.expires = new Date(Date.now() + options.maxAge)     options.maxAge \/= 1000   }    \/\/ \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a `Set-Cookie`   res.setHeader('Set-Cookie', serialize(name, String(stringValue), options)) }  const cookies: NextApiMiddleware&lt;   NextApiHandlerWithCookie,   NextApiResponseWithCookie > = (handler) => (req, res) => {   \/\/ \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u043e\u0442\u0432\u0435\u0442\u0430   res.cookie = (args: CookieArgs) => cookieFn(res, args)    \/\/ \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443   return handler(req, res) }  export default cookies<\/code><\/pre>\n<p>  <\/p>\n<p>\u042d\u0442\u043e\u0442 \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043a\u0443\u043a\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>res.cookie({ name, value, options })<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0432 \u043d\u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { NextApiHandlerWithCookie } from '@\/types' import cookies from '@\/utils\/cookie'  const handler: NextApiHandlerWithCookie = async (req, res) => {   console.log(res.cookie)   \/\/ ... }  export default cookies(handler)<\/code><\/pre>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a\u0430 \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c \u0432 \u0444\u0430\u0439\u043b\u0435 <code>utils\/authGuard.ts<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import jwt from 'jsonwebtoken' import { NextApiHandler, NextApiResponse } from 'next' import { NextApiMiddleware } from '..\/types'  const authGuard: NextApiMiddleware&lt;NextApiHandler, NextApiResponse> =   (handler) => async (req, res) => {     \/\/ \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0438\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 `Authorization`     \/\/ \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u044d\u0442\u043e\u0433\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0430 `Bearer [accessToken]`     const accessToken = req.headers.authorization?.split(' ')[1]      \/\/ \u0435\u0441\u043b\u0438 \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442     if (!accessToken) {       return res.status(403).json({ message: 'Access token must be provided' })     }      \/\/ \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u0443\u0435\u043c \u0442\u043e\u043a\u0435\u043d     \/\/ \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0430 \u0442\u043e\u043a\u0435\u043d\u0430 - `{ payload: string }`     const decodedToken = (await jwt.verify(       accessToken,       process.env.ACCESS_TOKEN_SECRET     )) as unknown as {       payload: string     }      \/\/ \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u043b\u0438 \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435     if (       !decodedToken ||       decodedToken.payload !== process.env.ACCESS_TOKEN_PAYLOAD     ) {       return res.status(403).json({ message: 'Invalid token' })     }      \/\/ \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443     return handler(req, res)   }  export default authGuard<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0443\u0442\u0438\u043b\u0438\u0442\u0443 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u0432 \u0442\u0435\u043b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>utils\/checkFields.ts<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export default function checkFields&lt;T>(obj: T, keys: Array&lt;keyof T>) {   for (const key of keys) {     if (!obj[key]) {       return false     }   }   return true }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u0443\u043c\u0430\u044e, \u0437\u0434\u0435\u0441\u044c \u0432\u0441\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e.<\/p>\n<p>  <\/p>\n<h3 id=\"routy-autentifikacii-i-avtorizacii\">\u0420\u043e\u0443\u0442\u044b \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/h3>\n<p>  <\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0440\u043e\u0443\u0442\u043e\u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>pages\/api<\/code> \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <code>\/api\/*<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0432 \u043d\u0435\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>auth<\/code> \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 <code>register.ts<\/code> \u0438 <code>login.ts<\/code>.<\/p>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0440\u043e\u0443\u0442 \u0434\u043b\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { NextApiHandlerWithCookie } from '@\/types' import checkFields from '@\/utils\/checkFields' import cookies from '@\/utils\/cookie' import prisma from '@\/utils\/prisma' import { User } from '@prisma\/client' import argon2 from 'argon2' import jwt from 'jsonwebtoken'  const registerHandler: NextApiHandlerWithCookie = async (req, res) => {   \/\/ \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0442\u0435\u043b\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430   \/\/ \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Prisma \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0442\u0438\u043f\u043e\u0432 \u043c\u043e\u0434\u0435\u043b\u0435\u0439   const data: Pick&lt;User, 'username' | 'email' | 'password'> = JSON.parse(     req.body   )    \/\/ \u0435\u0441\u043b\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u043d\u043e \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435   if (!checkFields(data, ['email', 'password'])) {     return res.status(400).json({ message: 'Some required fields are missing' })   }    try {     \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     const existingUser = await prisma.user.findUnique({       where: { email: data.email }     })      \/\/ \u0435\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u043c\u0435\u044e\u0442\u0441\u044f, \u0437\u043d\u0430\u0447\u0438\u0442, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d     if (existingUser) {       return res.status(409).json({ message: 'Email already in use' })     }      \/\/ \u0445\u044d\u0448\u0438\u0440\u0443\u0435\u043c \u043f\u0430\u0440\u043e\u043b\u044c     const passwordHash = await argon2.hash(data.password)     \/\/ \u0438 \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u043c \u0438\u043c \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439     data.password = passwordHash      \/\/ \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f - \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0443\u0447\u0435\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0411\u0414     const newUser = await prisma.user.create({       data,       \/\/ \u0432\u0430\u0436\u043d\u043e!       \/\/ \u043d\u0435 \"\u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c\" \u043f\u0430\u0440\u043e\u043b\u044c       select: {         id: true,         username: true,         email: true       }     })      \/\/ \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 ID \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     const idToken = await jwt.sign(       { userId: newUser.id },       process.env.ID_TOKEN_SECRET,       {         \/\/ \u0441\u0440\u043e\u043a \u0436\u0438\u0437\u043d\u0438 \u0442\u043e\u043a\u0435\u043d\u0430, \u0442.\u0435. \u0432\u0440\u0435\u043c\u044f, \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d \u0431\u0443\u0434\u0435\u0442 \u0441\u0447\u0438\u0442\u0430\u0442\u044c\u0441\u044f \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 7 \u0434\u043d\u0435\u0439         expiresIn: '7d'       }     )      \/\/ \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0439 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0443     const accessToken = await jwt.sign(       { payload: process.env.ACCESS_TOKEN_PAYLOAD },       process.env.ACCESS_TOKEN_SECRET,       {         \/\/ \u0432\u0430\u0436\u043d\u043e!         \/\/ \u0442\u0430\u043a\u043e\u0439 \u0441\u0440\u043e\u043a \u0436\u0438\u0437\u043d\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f         \/\/ \u0441\u043c. \u043d\u0438\u0436\u0435         expiresIn: '1d'       }     )      \/\/ \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432 \u043a\u0443\u043a\u0438     res.cookie({       name: process.env.COOKIE_NAME,       value: idToken,       \/\/ https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Set-Cookie#attributes       \/\/ \u0432\u0430\u0436\u043d\u043e!       \/\/ \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 `httpOnly: true` \u0438 `secure: true` \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438       options: {         httpOnly: true,         \/\/ \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043e\u043b\u0436\u043d\u043e \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0442\u044c \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 `expiresIn` \u0442\u043e\u043a\u0435\u043d\u0430         maxAge: 1000 * 60 * 60 * 24 * 7,         \/\/ \u043a\u0443\u043a\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f         path: '\/',         \/\/ \u043a\u043b\u0438\u0435\u043d\u0442 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0436\u0438\u0432\u0443\u0442 \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443 \u0430\u0434\u0440\u0435\u0441\u0443         sameSite: true,         secure: true       }     })      \/\/ \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430     res.status(200).json({       user: newUser,       accessToken     })   } catch (e) {     console.log(e)     res.status(500).json({ message: 'User register error' })   } }  export default cookies(registerHandler)<\/code><\/pre>\n<p>  <\/p>\n<p>\u041c\u044b \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0441 \u043e\u0447\u0435\u043d\u044c \u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0441\u0440\u043e\u043a\u043e\u043c \u0436\u0438\u0437\u043d\u0438. \u042d\u0442\u043e \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430\u0441 \u043e\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0435\u0433\u043e \u043f\u0440\u043e\u0434\u043b\u0435\u043d\u0438\u044f (\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430) \u0432 \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a\u0435 <code>authGuard<\/code>, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440. \u041d\u043e \u044d\u0442\u043e \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0441\u0440\u043e\u043a \u0436\u0438\u0437\u043d\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 1 \u0447\u0430\u0441. \u0422\u0430\u043a\u0436\u0435 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u043e\u0434\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438: \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0432\u0445\u043e\u0434 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0432 \u043d\u0435\u0434\u0435\u043b\u044e.<\/p>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0440\u043e\u0443\u0442 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { NextApiHandlerWithCookie } from '@\/types' import checkFields from '@\/utils\/checkFields' import cookies from '@\/utils\/cookie' import prisma from '@\/utils\/prisma' import { User } from '@prisma\/client' import argon2 from 'argon2' import jwt from 'jsonwebtoken'  const loginHandler: NextApiHandlerWithCookie = async (req, res) => {   const data: Pick&lt;User, 'email' | 'password'> = JSON.parse(req.body)    if (!checkFields(data, ['email', 'password'])) {     return res.status(400).json({ message: 'Some required fields are missing' })   }    try {     \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     const user = await prisma.user.findUnique({       where: {         email: data.email       },       \/\/ \u0432\u0430\u0436\u043d\u043e!       \/\/ \u0437\u0434\u0435\u0441\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043f\u0430\u0440\u043e\u043b\u044c       select: {         id: true,         email: true,         password: true,         username: true,         avatarUrl: true       }     })      \/\/ \u0435\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442     if (!user) {       return res.status(404).json({ message: 'User not found' })     }      \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043f\u0430\u0440\u043e\u043b\u044c     const isPasswordCorrect = await argon2.verify(user.password, data.password)      \/\/ \u0435\u0441\u043b\u0438 \u0432\u0432\u0435\u0434\u0435\u043d \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c     if (!isPasswordCorrect) {       return res.status(403).json({ message: 'Wrong password' })     }      \/\/ \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438     const idToken = await jwt.sign(       { userId: user.id },       process.env.ID_TOKEN_SECRET,       {         expiresIn: '7d'       }     )      \/\/ \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430     const accessToken = await jwt.sign(       { payload: process.env.ACCESS_TOKEN_PAYLOAD },       process.env.ACCESS_TOKEN_SECRET,       {         expiresIn: '1d'       }     )      \/\/ \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432 \u043a\u0443\u043a\u0438     res.cookie({       name: process.env.COOKIE_NAME,       value: idToken,       options: {         httpOnly: true,         maxAge: 1000 * 60 * 60 * 24 * 7,         path: '\/',         sameSite: true,         secure: true       }     })      \/\/ \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u0431\u0435\u0437 \u043f\u0430\u0440\u043e\u043b\u044f!)     \/\/ \u0438 \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430     res.status(200).json({       user: {         id: user.id,         email: user.email,         username: user.username,         avatarUrl: user.avatarUrl       },       accessToken     })   } catch (e) {     console.log(e)     res.status(500).json({ message: 'User login error' })   } }  export default cookies(loginHandler)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b <code>auth\/user.ts<\/code> \u0434\u043b\u044f \u0440\u043e\u0443\u0442\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import prisma from '@\/utils\/prisma' import jwt from 'jsonwebtoken' import { NextApiHandler } from 'next'  const userHandler: NextApiHandler = async (req, res) => {   \/\/ \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438\u0437 \u043a\u0443\u043a\u0438   const idToken = req.cookies[process.env.COOKIE_NAME]    \/\/ \u0435\u0441\u043b\u0438 \u0442\u043e\u043a\u0435\u043d \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442   if (!idToken) {     return res.status(401).json({ message: 'ID token must be provided' })   }    try {     \/\/ \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u0443\u0435\u043c \u0442\u043e\u043a\u0435\u043d     const decodedToken = (await jwt.verify(       idToken,       process.env.ID_TOKEN_SECRET     )) as unknown as { userId: string }      \/\/ \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442     if (!decodedToken || !decodedToken.userId) {       return res.status(403).json({ message: 'Invalid token' })     }      \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     const user = await prisma.user.findUnique({       where: { id: decodedToken.userId },       \/\/ \u0432\u0430\u0436\u043d\u043e!       \/\/ \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u0430\u0440\u043e\u043b\u044c       select: {         id: true,         email: true,         username: true,         avatarUrl: true       }     })      \/\/ \u0435\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442     if (!user) {       return res.status(404).json({ message: 'User not found' })     }      \/\/ \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430     const accessToken = await jwt.sign(       { payload: process.env.ACCESS_TOKEN_PAYLOAD },       process.env.ACCESS_TOKEN_SECRET,       {         expiresIn: '1d'       }     )      \/\/ \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430     res.status(200).json({ user, accessToken })   } catch (e) {     console.log(e)     res.status(500).json({ message: 'User get error' })   } }  export default userHandler<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0440\u043e\u0443\u0442 \u0434\u043b\u044f \u0432\u044b\u0445\u043e\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0432 \u0444\u0430\u0439\u043b\u0435 <code>auth\/logout.ts<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { NextApiHandlerWithCookie } from '@\/types' import authGuard from '@\/utils\/authGuard' import cookies from '@\/utils\/cookie'  const logoutHandler: NextApiHandlerWithCookie = async (req, res) => {   \/\/ \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u044b\u0445\u043e\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043a\u0443\u043a\u0438   res.cookie({     name: process.env.COOKIE_NAME,     value: '',     options: {       httpOnly: true,       maxAge: 0,       path: '\/',       sameSite: true,       secure: true     }   })    res.status(200).json({ message: 'Logout success' }) }  \/\/ \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u0440\u043e\u0443\u0442 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u043c export default authGuard(cookies(logoutHandler) as any)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438 4 \u0440\u043e\u0443\u0442\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>POST \/api\/register<\/code> \u2014 \u0434\u043b\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f;<\/li>\n<li><code>POST \/api\/login<\/code> \u2014 \u0434\u043b\u044f \u0432\u0445\u043e\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443;<\/li>\n<li><code>GET \/api\/user<\/code> \u2014 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f;<\/li>\n<li><code>GET \/api\/logout<\/code> \u2014 \u0434\u043b\u044f \u0432\u044b\u0445\u043e\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u0441\u0438\u0441\u0442\u0435\u043c\u044b.<\/li>\n<\/ul>\n<p>  <\/p>\n<h2 id=\"zagruzka-faylov\">\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432<\/h2>\n<p>  <\/p>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0430\u0432\u0430\u0442\u0430\u0440\u044b. \u0421\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u043e\u0443\u0442 \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u043e\u0432 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u0438\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f Multer.<\/p>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0441\u0435\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0440\u043e\u0443\u0442\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f <code>next-connect<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>api<\/code> \u0444\u0430\u0439\u043b <code>upload.ts<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import authGuard from '@\/utils\/authGuard' import prisma from '@\/utils\/prisma' import multer from 'multer' import { NextApiRequest, NextApiResponse } from 'next' import nextConnect from 'next-connect'  \/\/ \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0444\u0430\u0439\u043b\u043e\u0432 const upload = multer({   storage: multer.diskStorage({     \/\/ \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0430\u0432\u0430\u0442\u043e\u0440\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439     destination: '.\/public\/avatars',     \/\/ \u0432\u0430\u0436\u043d\u043e!     \/\/ \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u0444\u0430\u0439\u043b\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f + \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430     \/\/ \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435     filename: (req, file, cb) => cb(null, file.originalname)   }) })  \/\/ \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0440\u043e\u0443\u0442 const uploadHandler = nextConnect&lt;   NextApiRequest &amp; { file?: Express.Multer.File },   NextApiResponse >()  \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a\u0430 \/\/ \u0432\u0430\u0436\u043d\u043e! \/\/ \u043f\u043e\u043b\u0435 \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0444\u0430\u0439\u043b\u0430 \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f `avatar` \/\/ &lt;input type=\"file\" name=\"avatar\" \/> uploadHandler.use(upload.single('avatar'))  \/\/ \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c POST-\u0437\u0430\u043f\u0440\u043e\u0441 uploadHandler.post(async (req, res) => {   \/\/ multer \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0444\u0430\u0439\u043b \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 `public\/avatars`   \/\/ \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u0430 \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 `req.file`   if (!req.file) {     return res.status(500).json({ message: 'File write error' })   }    \/\/ \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c ID \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430   const userId = req.file.filename.split('.')[0]    try {     \/\/ \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     const user = await prisma.user.update({       where: { id: userId },       data: {         \/\/ \u0443\u0434\u0430\u043b\u044f\u0435\u043c `public`         avatarUrl: req.file.path.replace('public', '')       },       \/\/ \u0432\u0430\u0436\u043d\u043e!       \/\/ \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u0430\u0440\u043e\u043b\u044c       select: {         id: true,         username: true,         avatarUrl: true,         email: true       }     })      \/\/ \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     res.status(200).json(user)   } catch (e) {     console.error(e)     res.status(500).json({ message: 'User update error' })   } })  \/\/ \u0440\u043e\u0443\u0442 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u043c export default authGuard(uploadHandler)  \/\/ \u0432\u0430\u0436\u043d\u043e! \/\/ \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0435\u043b\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 JSON export const config = {   api: {     bodyParser: false   } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u042d\u0442\u043e\u0442 \u0440\u043e\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <code>\/api\/upload<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 <code>POST<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0432 \u043d\u0430\u0448\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u043b\u043e\u0433\u0438\u043a\u0438 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u0440\u044b\u0445 \u0430\u0432\u0430\u0442\u0430\u0440\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439: \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 ID \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430, \u0442.\u0435. \u043e\u0434\u0438\u043d \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b\u043e\u0432 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f\u043c\u0438. \u042d\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b\u043e\u0432 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u043f\u043e\u043b\u0435 <code>avatarUrl<\/code> \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b. \u0422\u0430\u043a\u0436\u0435 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u043b\u044f \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0443\u0442\u0435\u043c \u0435\u0433\u043e \u0441\u0436\u0430\u0442\u0438\u044f.<\/p>\n<p>  <\/p>\n<h2 id=\"crud-operacii-dlya-postov-i-laykov\">CRUD-\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u043e\u0432 \u0438 \u043b\u0430\u0439\u043a\u043e\u0432<\/h2>\n<p>  <\/p>\n<p>\u0421\u0435\u0440\u0432\u0435\u0440\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0447\u0442\u0438 \u0433\u043e\u0442\u043e\u0432\u0430. \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u043e\u0443\u0442\u044b \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f, \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043b\u0430\u0439\u043a\u043e\u0432.<\/p>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u0432\u0441\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0440\u043e\u0443\u0442\u044b \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u043c\u0438.<\/p>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 <em>\u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>, \u0447\u0442\u043e \u0440\u043e\u0443\u0442\u044b \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u0441\u0442\u043e\u0432 \u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u0441\u0442\u0430 \u043f\u043e ID \u0431\u0443\u0434\u0443\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435 (\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435) \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <a href=\"https:\/\/nextjs.org\/docs\/basic-features\/data-fetching\/get-server-side-props\">getServerSideProps<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>api<\/code> \u0444\u0430\u0439\u043b <code>post.ts<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import authGuard from '@\/utils\/authGuard' import checkFields from '@\/utils\/checkFields' import prisma from '@\/utils\/prisma' import { Post } from '@prisma\/client' import { NextApiRequest, NextApiResponse } from 'next' import nextConnect from 'next-connect'  const postsHandler = nextConnect&lt;NextApiRequest, NextApiResponse>()  \/\/ \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c POST-\u0437\u0430\u043f\u0440\u043e\u0441 \/\/ \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0430 postsHandler.post(async (req, res) => {   const data: Pick&lt;Post, 'title' | 'content' | 'authorId'> = JSON.parse(     req.body   )    if (!checkFields(data, ['title', 'content', 'authorId'])) {     res.status(400).json({ message: 'Some required fields are missing' })   }    try {     const post = await prisma.post.create({       data     })     res.status(200).json(post)   } catch (e) {     console.error(e)     res.status(500).json({ message: 'Post create error' })   } })  \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 PUT-\u0437\u0430\u043f\u0440\u043e\u0441\u0430 \/\/ \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0430 postsHandler.put(async (req, res) => {   const data: Pick&lt;Post, 'title' | 'content'> &amp; {     postId: string   } = JSON.parse(req.body)    if (!checkFields(data, ['title', 'content'])) {     res.status(400).json({ message: 'Some required fields are missing' })   }    try {     const post = await prisma.post.update({       where: { id: data.postId },       data: {         title: data.title,         content: data.content       }     })     res.status(200).json(post)   } catch (e) {     console.error(e)     res.status(500).json({ message: 'Update post error' })   } })  \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 DELETE-\u0437\u0430\u043f\u0440\u043e\u0441\u0430 \/\/ \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0430 postsHandler.delete(async (req, res) => {   const id = req.query.id as string    if (!id) {     return res.status(400).json({       message: 'Post ID is missing'     })   }    try {     const post = await prisma.post.delete({       where: {         id       }     })     res.status(200).json(post)   } catch (e) {     console.error(e)     res.status(500).json({ message: 'Post remove error' })   } })  export default authGuard(postsHandler)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u043e \u0432\u0441\u0435\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0432 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u0441\u0442\u0430.<\/p>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0443 \u043d\u0430\u0441 \u0438\u043c\u0435\u0435\u0442\u0441\u044f 3 \u0440\u043e\u0443\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0430:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>POST \/api\/post<\/code> \u2014 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u0430;<\/li>\n<li><code>PUT \/api\/post<\/code> \u2014 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u0430;<\/li>\n<li><code>DELETE \/api\/post?postId=&lt;post-id><\/code> \u2014 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u0430.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0440\u043e\u0443\u0442 \u0434\u043b\u044f \u043b\u0430\u0439\u043a\u043e\u0432 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>api\/like.ts<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import authGuard from '@\/utils\/authGuard' import checkFields from '@\/utils\/checkFields' import prisma from '@\/utils\/prisma' import { Like } from '@prisma\/client' import { NextApiRequest, NextApiResponse } from 'next' import nextConnect from 'next-connect'  const likeHandler = nextConnect&lt;NextApiRequest, NextApiResponse>()  \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 POST-\u0437\u0430\u043f\u0440\u043e\u0441\u0430 \/\/ \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043b\u0430\u0439\u043a\u0430 likeHandler.post(async (req, res) => {   const data = JSON.parse(req.body) as Omit&lt;Like, 'id'>    if (!checkFields(data, ['postId', 'userId'])) {     return res.status(400).json({ message: 'Some required fields are missing' })   }    try {     const like = await prisma.like.create({       data     })     res.status(201).json(like)   } catch (e) {     console.log(e)     res.status(500).json({ message: 'Like create error' })   } })  \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 DELETE-\u0437\u0430\u043f\u0440\u043e\u0441\u0430 \/\/ \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0430 likeHandler.delete(async (req, res) => {   const id = req.query.id as string    if (!id) {     return res.status(400).json({ message: 'Like ID is missing' })   }    try {     const like = await prisma.like.delete({       where: {         id       }     })     res.status(200).json(like)   } catch (e) {     console.log(e)     res.status(500).json({ message: 'Like remove error' })   } })  export default authGuard(likeHandler)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0443 \u043d\u0430\u0441 \u0438\u043c\u0435\u0435\u0442\u0441\u044f 2 \u0440\u043e\u0443\u0442\u0430 \u0434\u043b\u044f \u043b\u0430\u0439\u043a\u0430:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>POST \/api\/like<\/code> \u2014 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043b\u0430\u0439\u043a\u0430;<\/li>\n<li><code>DELETE \/api\/like?likeId=&lt;like-id><\/code> \u2014 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043b\u0430\u0439\u043a\u0430.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0448\u0442\u0440\u0438\u0445\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 HTTP, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c\u044e, \u0432 <code>next.config.js<\/code> \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0440\u043e\u0443\u0442\u043e\u0432:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/** @type {import('next').NextConfig} *\/ const securityHeaders = [   { key: 'X-Content-Type-Options', value: 'nosniff' },   { key: 'X-Frame-Options', value: 'DENY' },   { key: 'X-XSS-Protection', value: '1; mode=block' },   { key: 'Cross-Origin-Resource-Policy', value: 'same-site' },   {     key: 'Cross-Origin-Opener-Policy',     value: 'same-origin-allow-popups'   },   { key: 'Cross-Origin-Embedder-Policy', value: 'require-corp' },   { key: 'Referrer-Policy', value: 'no-referrer' },   {     key: 'Strict-Transport-Security',     value: 'max-age=31536000; includeSubDomains'   },   { key: 'Expect-CT', value: 'enforce, max-age=86400' },   {     key: 'Content-Security-Policy',     value: `object-src 'none'; frame-ancestors 'self'; block-all-mixed-content; upgrade-insecure-requests`   },   {     key: 'Permissions-Policy',     value: 'camera=(), microphone=(), geolocation=(), payment=()'   } ]  const nextConfig = {   reactStrictMode: true,   images: {     domains: ['images.unsplash.com']   },   async headers() {     return [       {         source: '\/:path*',         headers: securityHeaders       }     ]   } }  module.exports = nextConfig<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/my-js.org\/docs\/cheatsheet\/security-headers\">\u0428\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0430 \u043f\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438<\/a>.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041c\u044b \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0411\u0443\u0434\u0443 \u0440\u0430\u0434 \u043b\u044e\u0431\u044b\u043c \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u044f\u043c \u0438 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c.<\/p>\n<p>  <\/p>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0438 happy coding!<\/p>\n<p>  <\/p>\n<hr\/>\n<p>  <\/p>\n<p><a href=\"https:\/\/timeweb.cloud\/?utm_source=habr&amp;utm_medium=banner&amp;utm_campaign=vds-promo-6-rub\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/p-\/u9\/l2\/p-u9l27ynelxi92bcmdxhu76ma8.png\" data-src=\"https:\/\/habrastorage.org\/webt\/p-\/u9\/l2\/p-u9l27ynelxi92bcmdxhu76ma8.png\"\/><\/a><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p> <!----> <!----><\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/712294\/\"> https:\/\/habr.com\/ru\/company\/timeweb\/blog\/712294\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/by\/f9\/qu\/byf9qu-qkjvc3cpega2osikmrcq.png\" data-src=\"https:\/\/habrastorage.org\/webt\/by\/f9\/qu\/byf9qu-qkjvc3cpega2osikmrcq.png\"\/>  <\/p>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0442, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p>  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0438\u0437 2 \u0441\u0442\u0430\u0442\u0435\u0439-\u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u043e\u0432 \u043c\u044b \u0441 \u0432\u0430\u043c\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0435 (\u0444\u0443\u043b\u043b\u0441\u0442\u0435\u043a \u2014 fullstack) \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/nextjs.org\/\">Next.js<\/a> \u0438 <a href=\"https:\/\/www.typescriptlang.org\/\">TypeScript<\/a>.<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/my-js.org\/docs\/guide\/nextjs\">\u0420\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e Next.js<\/a>.<\/li>\n<li><a href=\"https:\/\/my-js.org\/docs\/guide\/ts\">\u041a\u0430\u0440\u043c\u0430\u043d\u043d\u0430\u044f \u043a\u043d\u0438\u0433\u0430 \u043f\u043e TypeScript<\/a>.<\/li>\n<\/ul>\n<p>  <\/p>\n<ol>\n<li>\u041d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0431\u043e\u0439 \u0431\u043b\u043e\u0433 \u2014 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438, \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u043e\u0432.<\/li>\n<li>\u041c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <a href=\"https:\/\/jwt.io\/\">JSON Web Tokens<\/a> \u0438 <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Cookies\">HTTP-\u043a\u0443\u043a\u0438<\/a>.<\/li>\n<li>\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u043f\u043e\u0441\u0442\u043e\u0432 \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0432 \u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 <a href=\"https:\/\/www.sqlite.org\/\">SQLite<\/a>.<\/li>\n<\/ol>\n<p>  <\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u043e\u043c \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0435 \u043c\u044b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0440\u043e\u0443\u0442\u043e\u0432 (API Routes), \u0432\u043e \u0432\u0442\u043e\u0440\u043e\u043c \u2014 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u0434\u0430\u043d\u043d\u044b\u0439 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d \u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043c\u0435\u044e\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u044b\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 <a href=\"https:\/\/ru.reactjs.org\/\">React<\/a> \u0438 <a href=\"https:\/\/nodejs.org\/\">Node.js<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0442\u0435\u0445, \u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0434, \u0432\u043e\u0442 <a href=\"https:\/\/github.com\/harryheman\/Blog-Posts\/tree\/master\/fullstack-next-ts-app\">\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e? \u0422\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-344376","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/344376","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=344376"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/344376\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=344376"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=344376"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=344376"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}