рдирдорд╕реНрдХрд╛рд░, рд╣реЗрдмреНрд░! рдореИрдВ рдЖрдкрдХреЛ рдПрдирд╛ рд░рд┐рдмреЗрд░реЛ рджреНрд╡рд╛рд░рд╛ рд▓реЗрдЦ "рдлреБрд▓-рд╕реНрдЯреИрдХ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдРрдкреНрд╕ - рднрд╛рдЧ 1: рд╡рд┐рдХрд╛рд╕рд╢реАрд▓ рдмреИрдХрдПрдВрдб рдПрдкреАрдЖрдИ рд╡рд┐рде рдиреЗрд╕реНрдЯ.рдЬреЗрдПрд╕" рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдкреЗрд╢ рдХрд░рддрд╛ рд╣реВрдВред
рднрд╛рдЧ 1: Nest.JS рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рд░реНрд╡рд░ API рдХрд╛ рд╡рд┐рдХрд╛рд╕ рдХрд░рдирд╛
TL; DR: рдпрд╣ рдХреИрд╕реЗ рдХреЛрдгреАрдп рдФрд░ Nest.JS рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╡реЗрдм рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдмрдирд╛рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╢реНрд░реГрдВрдЦрд▓рд╛ рд╣реИред рдкрд╣рд▓реЗ рднрд╛рдЧ рдореЗрдВ, рд╣рдо Nest.JS рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдПрдХ рд╕рд╛рдзрд╛рд░рдг рд╕рд░реНрд╡рд░ рдПрдкреАрдЖрдИ рд▓рд┐рдЦреЗрдВрдЧреЗред рдЗрд╕ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХрд╛ рджреВрд╕рд░рд╛ рд╣рд┐рд╕реНрд╕рд╛ рдХреЛрдгреАрдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдлреНрд░рдВрдЯ-рдПрдВрдб рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдкрд┐рдд рд╣реИред рдЖрдк рдЗрд╕ GitHub рднрдВрдбрд╛рд░ рдореЗрдВ рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рд╡рд┐рдХрд╕рд┐рдд рдЕрдВрддрд┐рдо рдХреЛрдб рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ ред
Nest.Js рдФрд░ рдХреНрдпреЛрдВ рдХреЛрдгреАрдп рд╣реИ?
Nest.js Node.js рд╡реЗрдм рд╕рд░реНрд╡рд░ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рд▓рд┐рдП рдПрдХ рд░реВрдкрд░реЗрдЦрд╛ рд╣реИред
рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╡рд┐рд╢реЗрд╖рддрд╛ рдпрд╣ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдРрд╕реА рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдХреЛрдИ рдЕрдиреНрдп рдврд╛рдВрдЪрд╛ рд╣рд▓ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ: рдиреЛрдб.рдЬреЗрдПрд╕ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреА рд╕рдВрд░рдЪрдирд╛ред рдпрджрд┐ рдЖрдкрдиреЗ рдХрднреА рднреА рдиреЛрдб.рдЬреЗрдПрд╕ рдХреЗ рддрд╣рдд рд╡рд┐рдХрд╕рд┐рдд рдХрд┐рдпрд╛ рд╣реИ, рддреЛ рдЖрдк рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдЖрдк рдПрдХ рдореЙрдбреНрдпреВрд▓ рдХреЗ рд╕рд╛рде рдмрд╣реБрдд рдХреБрдЫ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдорд┐рдбрд╡реЗрд╡реЗрдпрд░ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рд╕реЗ рд╕рддреНрдпрд╛рдкрди рддрдХ рд╕рдм рдХреБрдЫ рдХрд░ рд╕рдХрддрд╛ рд╣реИ), рдЬреЛ рдЕрдВрдд рдореЗрдВ, рдПрдХ рдЕрд╕рдорд░реНрдерд┐рдд "рдЧрдбрд╝рдмрдбрд╝" рдХрд╛ рдХрд╛рд░рдг рдмрди рд╕рдХрддрд╛ рд╣реИред ред рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдиреАрдЪреЗ рджреЗрдЦреЗрдВрдЧреЗ, nest.js рд╡рд┐рднрд┐рдиреНрди рдореБрджреНрджреЛрдВ рдХреЗ рд╡рд┐рд╢реЗрд╖рдЬреНрдЮ рд╡рд░реНрдЧ рдкреНрд░рджрд╛рди рдХрд░рдХреЗ рд╣рдорд╛рд░реА рд╕рд╣рд╛рдпрддрд╛ рдХрд░реЗрдВрдЧреЗред
Nest.js рдХреЛрдгреАрдп рд╕реЗ рдХрд╛рдлреА рдкреНрд░реЗрд░рд┐рдд рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рджреЛрдиреЛрдВ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдЖрдкрдХреЗ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рдХреБрдЫ рд╣рд┐рд╕реНрд╕реЛрдВ рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдпрд╛ рдЙрдиреНрд╣реЗрдВ рд░реЛрдХрдиреЗ рдХреЗ рд▓рд┐рдП рдЧрд╛рд░реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рджреЛрдиреЛрдВ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдЗрди рдЧрд╛рд░реНрдбреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ CanActivate рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдпрд╣ рдзреНрдпрд╛рди рд░рдЦрдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рдХрд┐ рдХреБрдЫ рд╕рдорд╛рди рдЕрд╡рдзрд╛рд░рдгрд╛рдУрдВ рдХреЗ рдмрд╛рд╡рдЬреВрдж, рджреЛрдиреЛрдВ рд╕рдВрд░рдЪрдирд╛рдПрдВ рдПрдХ-рджреВрд╕рд░реЗ рд╕реЗ рд╕реНрд╡рддрдВрддреНрд░ рд╣реИрдВред рдпрд╣реА рд╣реИ, рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рд╣рдо рдЕрдкрдиреЗ рдлреНрд░рдВрдЯ-рдПрдВрдб рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реНрд╡рддрдВрддреНрд░ рдПрдкреАрдЖрдИ рдмрдирд╛рдПрдВрдЧреЗ, рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рд╕реА рднреА рдЕрдиреНрдп рдврд╛рдВрдЪреЗ (рд░рд┐рдПрдХреНрдЯ, рд╡реАрдпреВ.рдЬреЗрдПрд╕ рдФрд░ рдЗрд╕реА рддрд░рд╣) рдХреЗ рд╕рд╛рде рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдСрдирд▓рд╛рдЗрди рдСрд░реНрдбрд░ рдХреЗ рд▓рд┐рдП рд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди
рдЗрд╕ рдЧрд╛рдЗрдб рдореЗрдВ, рд╣рдо рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдПрдВрдЧреЗ рдЬрд┐рд╕рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХрд┐рд╕реА рд░реЗрд╕реНрддрд░рд╛рдВ рдореЗрдВ рдСрд░реНрдбрд░ рджреЗ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рдЗрд╕ рддрд░реНрдХ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдЧрд╛:
- рдХреЛрдИ рднреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдореЗрдиреВ рджреЗрдЦ рд╕рдХрддрд╛ рд╣реИ;
- рдХреЗрд╡рд▓ рдПрдХ рдЕрдзрд┐рдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЯреЛрдХрд░реА рдореЗрдВ рд╕рд╛рдорд╛рди рдЬреЛрдбрд╝ рд╕рдХрддрд╛ рд╣реИ (рдПрдХ рдСрд░реНрдбрд░ рдХрд░реЗрдВ)
- рдХреЗрд╡рд▓ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдирдП рдореЗрдиреВ рдЖрдЗрдЯрдо рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВред
рд╕рд╛рджрдЧреА рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдмрд╛рд╣рд░реА рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ рдФрд░ рд╣рдорд╛рд░реА рд╕реНрдЯреЛрд░ рдЯреЛрдХрд░реА рдХреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗред
Nest.js рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреА рдлрд╝рд╛рдЗрд▓ рд╕рдВрд░рдЪрдирд╛ рдмрдирд╛рдирд╛
Nest.js рдХреЛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ Node.js (v.8.9.x рдпрд╛ рдЙрдЪреНрдЪрддрд░) рдФрд░ NPM рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рд╡реЗрдмрд╕рд╛рдЗрдЯ рд╕реЗ рдЖрдкрдХреЗ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд▓рд┐рдП Node.js рдбрд╛рдЙрдирд▓реЛрдб рдФрд░ рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░реЗрдВ (NPM рд╢рд╛рдорд┐рд▓ рд╣реИ)ред рдЬрдм рд╕рдм рдХреБрдЫ рд╕реНрдерд╛рдкрд┐рдд рд╣реЛ рдЬрд╛рдП, рддреЛ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ:
node -v
Nest.js рдХреЗ рд╕рд╛рде рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдмрдирд╛рдиреЗ рдХреЗ рд╡рд┐рднрд┐рдиреНрди рддрд░реАрдХреЗ рд╣реИрдВ; рд╡реЗ рдкреНрд░рд▓реЗрдЦрди рдореЗрдВ рдкрд╛рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдо nest-cli
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдЗрд╕реЗ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ:
npm i -g @nestjs/cli
рдЕрдЧрд▓рд╛, рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдХрдорд╛рдВрдб рдХреЗ рд╕рд╛рде рд╣рдорд╛рд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдмрдирд╛рдПрдВ:
nest new nest-restaurant-api
рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ, рдШреЛрдВрд╕рд▓рд╛ рд╣рдореЗрдВ рдПрдХ рдкреИрдХреЗрдЬ рдореИрдиреЗрдЬрд░ рдЪреБрдирдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣реЗрдЧрд╛: npm
рдпрд╛ yarn
рдпрджрд┐ рд╕рдм рдХреБрдЫ рдареАрдХ рд░рд╣рд╛, рддреЛ nest
рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдлрд╝рд╛рдЗрд▓ рд╕рдВрд░рдЪрдирд╛ рдмрдирд╛рдПрдЧрд╛:
nest-restaurant-api тФЬтФАтФА src тФВ тФЬтФАтФА app.controller.spec.ts тФВ тФЬтФАтФА app.controller.ts тФВ тФЬтФАтФА app.module.ts тФВ тФЬтФАтФА app.service.ts тФВ тФФтФАтФА main.ts тФЬтФАтФА test тФВ тФЬтФАтФА app.e2e-spec.ts тФВ тФФтФАтФА jest-e2e.json тФЬтФАтФА .gitignore тФЬтФАтФА .prettierrc тФЬтФАтФА nest-cli.json тФЬтФАтФА package.json тФЬтФАтФА package-lock.json тФЬтФАтФА README.md тФЬтФАтФА tsconfig.build.json тФЬтФАтФА tsconfig.json тФФтФАтФА tslint.json
рдмрдирд╛рдИ рдЧрдИ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдкрд░ рдЬрд╛рдПрдВ рдФрд░ рд╡рд┐рдХрд╛рд╕ рд╕рд░реНрд╡рд░ рд╢реБрд░реВ рдХрд░реЗрдВ:
рдПрдХ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдЦреЛрд▓реЗрдВ рдФрд░ http://localhost:3000
ред рд╕реНрдХреНрд░реАрди рдкрд░ рд╣рдо рджреЗрдЦреЗрдВрдЧреЗ:

рдЗрд╕ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдХреЗ рднрд╛рдЧ рдХреЗ рд░реВрдк рдореЗрдВ, рд╣рдо рдЕрдкрдиреЗ рдПрдкреАрдЖрдИ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ (рд╣рд╛рд▓рд╛рдБрдХрд┐ рдЖрдкрдХреЛ рдХрд┐рд╕реА рднреА рддреИрдпрд╛рд░-рд╕реЗ-рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП)ред рдЗрд╕ рддрд░рд╣ рдЖрдк test
рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдХреЛ рд╕рд╛рдлрд╝ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ src/app.controller.spec.ts
(рдЬреЛ рдкрд░реАрдХреНрд╖рдг рдПрдХ рд╣реИ) рдХреЛ рд╣рдЯрд╛ рд╕рдХрддреЗ рд╣реИрдВред рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рд╣рдорд╛рд░реЗ рд╕реНрд░реЛрдд рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рдирд┐рдореНрди рдлрд╝рд╛рдЗрд▓реЗрдВ рд╣реИрдВ:
src/app.controller.ts
рдФрд░ src/app.module.ts
: рдпреЗ рдлрд╛рдЗрд▓реЗрдВ /
рдорд╛рд░реНрдЧ рдХреЗ рд╕рд╛рде Hello world
рд╕рдВрджреЗрд╢ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИрдВред рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдмрд┐рдВрджреБ рдЗрд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП рдорд╣рддреНрд╡рдкреВрд░реНрдг рдирд╣реАрдВ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдЙрдиреНрд╣реЗрдВ рд╣рдЯрд╛рддреЗ рд╣реИрдВред рдЬрд▓реНрдж рд╣реА рдЖрдк рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рдЬрд╛рдиреЗрдВрдЧреЗ рдХрд┐ рдирд┐рдпрдВрддреНрд░рдХ рдФрд░ рд╕реЗрд╡рд╛рдПрдВ рдХреНрдпрд╛ рд╣реИрдВ редsrc/app.module.ts
: рдореЗрдВ рдкреНрд░рдХрд╛рд░ рдореЙрдбреНрдпреВрд▓ рдХреЗ рдПрдХ рд╡рд░реНрдЧ рдХрд╛ рд╡рд┐рд╡рд░рдг рд╢рд╛рдорд┐рд▓ рд╣реИ, рдЬреЛ рдХрд┐ рдШреЛрдВрд╕рд▓реЗ рдХреЗ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдФрд░ рдкреНрд░рджрд╛рддрд╛рдУрдВ рдХреЗ рдЖрдпрд╛рдд, рдирд┐рд░реНрдпрд╛рдд рдХреЛ рдШреЛрд╖рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдХрдо рд╕реЗ рдХрдо рдПрдХ рдореЙрдбреНрдпреВрд▓ рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЖрдк рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдПрдкреНрд▓рд┐рдХреЗрд╢рди ( рдкреНрд░рд▓реЗрдЦрди рдореЗрдВ рдЕрдзрд┐рдХ) рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдореЙрдбреНрдпреВрд▓ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдорд╛рд░рд╛ рдЖрд╡реЗрджрди рдХреЗрд╡рд▓ рдПрдХ рдореЙрдбреНрдпреВрд▓ рд╣реЛрдЧрд╛редsrc/main.ts
: рдпрд╣ рд╕рд░реНрд╡рд░ рдХреЛ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рдлрд╛рдЗрд▓ рд╣реИред
рдиреЛрдЯ: src/app.controller.ts
рдФрд░ src/app.module.ts
рдХреЛ рд╣рдЯрд╛рдиреЗ рдХреЗ рдмрд╛рдж src/app.module.ts
рдЖрдк рдЕрдкрдирд╛ рдЖрд╡реЗрджрди рд╢реБрд░реВ рдирд╣реАрдВ рдХрд░ рдкрд╛рдПрдВрдЧреЗред рдЪрд┐рдВрддрд╛ рди рдХрд░реЗрдВ, рд╣рдо рдЗрд╕реЗ рдЬрд▓реНрдж рд╣реА рдареАрдХ рдХрд░ рджреЗрдВрдЧреЗред
рдкреНрд░рд╡реЗрд╢ рдмрд┐рдВрджреБ (рд╕рдорд╛рдкрди рдмрд┐рдВрджреБ) рдмрдирд╛рдПрдВ
рд╣рдорд╛рд░рд╛ рдПрдкреАрдЖрдИ /items
рдорд╛рд░реНрдЧ рдкрд░ рдЙрдкрд▓рдмреНрдз рд╣реЛрдЧрд╛ред рдЗрд╕ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдмрд┐рдВрджреБ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдореЗрдиреВ рдХрд╛ рдкреНрд░рдмрдВрдзрди рдХрд░рддреЗ рд╣реИрдВред рдЪрд▓реЛ рдЗрд╕реЗ рдмрдирд╛рддреЗ рд╣реИрдВред
рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, src
рдЕрдВрджрд░ items
рдирд╛рдордХ рдПрдХ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдмрдирд╛рдПрдВред /items
рд░реВрдЯ рд╕реЗ рдЬреБрдбрд╝реА рд╕рднреА рдлрд╛рдЗрд▓реЗрдВ рдЗрд╕ рдирдИ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХреА рдЬрд╛рдПрдВрдЧреАред
рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рдирд╛
nest.js
, рдХрдИ рдЕрдиреНрдп рд░реВрдкрд░реЗрдЦрд╛рдУрдВ рдХреА рддрд░рд╣, рдирд┐рдпрдВрддреНрд░рдХ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рд╡рд╛рд▓реЗ рдорд╛рдирдЪрд┐рддреНрд░рдг рдорд╛рд░реНрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИрдВред nest.js
рдореЗрдВ рдПрдХ рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП nest.js
рдбреЗрдХреЛрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХрд░реЗрдВ: @Controller(${ENDPOINT})
ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╡рд┐рднрд┐рдиреНрди HTTP
рд╡рд┐рдзрд┐рдпреЛрдВ, рдЬреИрд╕реЗ GET
рдФрд░ POST
, рдХреЛ рдореИрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдЬреНрдЬрд╛рдХрд╛рд░ @Get
, @Post
, @Delete
, рдЖрджрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдореЗрдВ рдПрдХ рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬреЛ рд░реЗрд╕реНрддрд░рд╛рдВ рдореЗрдВ рдЙрдкрд▓рдмреНрдз рд╡реНрдпрдВрдЬрди рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рдФрд░ рдЬреЛ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдореЗрдиреВ рдХреА рд╕рд╛рдордЧреНрд░реА рдХрд╛ рдкреНрд░рдмрдВрдзрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдЖрдЗрдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рд╛рдордЧреНрд░рд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде src/items
рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ items.controller.tc
рдирд╛рдордХ рдПрдХ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ:
import { Get, Post, Controller } from '@nestjs/common'; @Controller('items') export class ItemsController { @Get() async findAll(): Promise<string[]> { return ['Pizza', 'Coke']; } @Post() async create() { return 'Not yet implemented'; } }
рд╣рдорд╛рд░реЗ рдирдП рдирд┐рдпрдВрддреНрд░рдХ рдХреЛ рд╣рдорд╛рд░реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдЙрдкрд▓рдмреНрдз рдХрд░рд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЗрд╕реЗ рдореЙрдбреНрдпреВрд▓ рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдХрд░реЗрдВ:
import { Module } from '@nestjs/common'; import { ItemsController } from './items/items.controller'; @Module({ imports: [], controllers: [ItemsController], providers: [], }) export class AppModule {}
рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреЛ рд▓реЙрдиреНрдЪ рдХрд░реЗрдВ: npm run start:dev
рдФрд░ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдЦреЛрд▓реЗрдВ http: // localhost: 3000 / items , рдЕрдЧрд░ рдЖрдкрдиреЗ рд╕рдм рдХреБрдЫ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХрд┐рдпрд╛ рд╣реИ, рддреЛ рд╣рдореЗрдВ рд╣рдорд╛рд░реЗ рдЕрдиреБрд░реЛрдз рдХрд╛ рдЬрд╡рд╛рдм рджреЗрдЦрдирд╛ рдЪрд╛рд╣рд┐рдП: ['Pizza', 'Coke']
ред
рдЕрдиреБрд╡рд╛рджрдХ рдХрд╛ рдиреЛрдЯ: рдирдП рдирд┐рдпрдВрддреНрд░рдХ, рд╕рд╛рде рд╣реА nest.js
рдЕрдиреНрдп рддрддреНрд╡реЛрдВ рдХреЛ nest.js
рдХреЗ рд▓рд┐рдПред nest.js
: рд╕реЗрд╡рд╛рдПрдВ, рдкреНрд░рджрд╛рддрд╛, рдЖрджрд┐, рдпрд╣ nest-cli
рд╕реЗ nest generate
рдХрдорд╛рдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдКрдкрд░ рд╡рд░реНрдгрд┐рдд рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк nest generate controller items
рдХрдорд╛рдВрдб nest generate controller items
рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рдШреЛрдВрд╕рд▓рд╛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рд╛рдордЧреНрд░реА рдХреЗ src/items/items.controller.tc
src/items/items.controller.spec.tc
рдФрд░ src/items/items.controller.tc
:
import { Get, Post, Controller } from '@nestjs/common'; @Controller('items') export class ItemsController {}
рдФрд░ app.molule.tc
рдореЗрдВ рдЗрд╕реЗ рдкрдВрдЬреАрдХреГрдд рдХрд░реЗрдВ
рдПрдХ рд╕реЗрд╡рд╛ рдХреЛ рдЬреЛрдбрд╝рдирд╛
рдЕрдм, рдЬрдм /items
рдПрдХреНрд╕реЗрд╕ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдорд╛рд░рд╛ рдЖрд╡реЗрджрди рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд░реЛрдз рдХреЗ рд▓рд┐рдП рдПрдХ рд╣реА рд╕рд░рдгреА рджреЗрддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдо рдмрджрд▓ рдирд╣реАрдВ рд╕рдХрддреЗ рд╣реИрдВред рдбреЗрдЯрд╛ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдирд╛ рдФрд░ рд╕рд╣реЗрдЬрдирд╛ рдирд┐рдпрдВрддреНрд░рдХ рдХрд╛ рд╡реНрдпрд╡рд╕рд╛рдп рдирд╣реАрдВ рд╣реИ, рдЗрд╕ рдЙрджреНрджреЗрд╢реНрдп рдХреЗ рд▓рд┐рдП рд╕реЗрд╡рд╛рдУрдВ рдХрд╛ рдЙрджреНрджреЗрд╢реНрдп n.js рд╣реИ
рдШреЛрдВрд╕рд▓реЗ рдореЗрдВ рд╕реЗрд╡рд╛рдПрдБ @Injectable
рдбреЗрдХреЛрд░реЗрдЯрд░ рдХрд╛ рдирд╛рдо рд╕реНрд╡рдпрдВ рдХреЗ рд▓рд┐рдП рдмреЛрд▓рддрд╛ рд╣реИ, рдЗрд╕ рдбреЗрдХреЛрд░реЗрдЯрд░ рдХреЛ рдХрдХреНрд╖рд╛ рдореЗрдВ рдЬреЛрдбрд╝рдиреЗ рд╕реЗ рдпрд╣ рдЕрдиреНрдп рдШрдЯрдХреЛрдВ рдЬреИрд╕реЗ рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯреЗрдмрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред
рдЪрд▓реЛ рд╣рдорд╛рд░реА рд╕реЗрд╡рд╛ рдмрдирд╛рдПрдБред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рд╛рде items.service.ts
рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ items.service.ts
рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ:
import { Injectable } from '@nestjs/common'; @Injectable() export class ItemsService { private readonly items: string[] = ['Pizza', 'Coke']; findAll(): string[] { return this.items; } create(item: string) { this.items.push(item); } }
рдФрд░ рд╣рдорд╛рд░реА рд╕реЗрд╡рд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП items.controller.ts
рдХрдВрдЯреНрд░реЛрд▓рд░ ( items.controller.ts
рдореЗрдВ рдШреЛрд╖рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред items.controller.ts
) items.controller.ts
:
import { Get, Post, Body, Controller } from '@nestjs/common'; import { ItemsService } from './items.service'; @Controller('items') export class ItemsController { constructor(private readonly itemsService: ItemsService) {} @Get() async findAll(): Promise<string[]> { return this.itemsService.findAll(); } @Post() async create(@Body() item: string) { this.itemsService.create(item); } }
рдирд┐рдпрдВрддреНрд░рдХ рдХреЗ рдирдП рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ, рд╣рдордиреЗ рд╡рд┐рдзрд┐ рд╡рд┐рдзрд┐ рддрд░реНрдХ create
рд▓рд┐рдП @Body
рдбреЗрдХреЛрд░реЗрдЯрд░ рдХреЛ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ред рдпрд╣ рддрд░реНрдХ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ req.body ['item']
рдорд╛рдзреНрдпрдо рд╕реЗ рдкрд╛рд╕ рдХрд┐рдП рдЧрдП рдбреЗрдЯрд╛ рдХреЛ рддрд░реНрдХ рд╕реЗ (рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, item
) рдореЗрдВ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдорд┐рд▓рд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдорд╛рд░реЗ рдирд┐рдпрдВрддреНрд░рдХ рдХреЛ ItemsService
рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкреНрд░рд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред ItemsService
рдХреЛ ItemsService
рд░реВрдк рдореЗрдВ рдШреЛрд╖рд┐рдд ItemsService
private readonly
рддреМрд░ рдкрд░ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЛ ItemsService
рдФрд░ рдХреЗрд╡рд▓ рдХрдХреНрд╖рд╛ рдХреЗ рдЕрдВрджрд░ рджреГрд╢реНрдпрдорд╛рди рдмрдирд╛рддрд╛ рд╣реИред
рдФрд░ app.module.ts
рдореЗрдВ рд╣рдорд╛рд░реА рд╕реЗрд╡рд╛ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рдирд╛ рди рднреВрд▓реЗрдВ:
import { Module } from '@nestjs/common'; import { ItemsController } from './items/items.controller'; import { ItemsService } from './items/items.service'; @Module({ imports: [], controllers: [ItemsController], providers: [ItemsService], }) export class AppModule {}
рд╕рднреА рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рдмрд╛рдж, рдЖрдЗрдП рдореЗрдиреВ рдореЗрдВ HTTP POST рдЕрдиреБрд░реЛрдз рднреЗрдЬреЗрдВ:
curl -X POST -H 'content-type: application/json' -d '{"item": "Salad"}' localhost:3000/items
рдлрд┐рд░ рд╣рдо рдЬрд╛рдВрдЪреЗрдВрдЧреЗ рдХрд┐ рдХреНрдпрд╛ GET рдЕрдиреБрд░реЛрдз (рдпрд╛ http: // localhost: 3000 / рдПрдХ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдЖрдЗрдЯрдо ) рдХрд░рдХреЗ рд╣рдорд╛рд░реЗ рдореЗрдиреВ рдкрд░ рдирдП рд╡реНрдпрдВрдЬрди рджрд┐рдЦрд╛рдИ рджрд┐рдП рд╣реИрдВ рдпрд╛ рдирд╣реАрдВ
curl localhost:3000/items
рд╢реЙрдкрд┐рдВрдЧ рдХрд╛рд░реНрдЯ рд░реВрдЯ рдмрдирд╛рдирд╛
рдЕрдм рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣рдорд╛рд░реЗ рдПрдкреАрдЖрдИ рдХреЗ рдкреНрд░рд╡реЗрд╢ рдмрд┐рдВрджреБ /items
рдкрд╣рд▓рд╛ рд╕рдВрд╕реНрдХрд░рдг рд╣реИ, рддреЛ рдЪрд▓реЛ рд╢реЙрдкрд┐рдВрдЧ рдХрд╛рд░реНрдЯ рдХреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рдмрдирд╛рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкрд╣рд▓реЗ рд╕реЗ рдирд┐рд░реНрдорд┐рдд рдПрдкреАрдЖрдИ рд╕реЗ рдмрд╣реБрдд рдЕрд▓рдЧ рдирд╣реАрдВ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдореИрдиреБрдЕрд▓ рдХреЛ рдЕрд╡реНрдпрд╡рд╕реНрдерд┐рдд рдирд╣реАрдВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдШрдЯрдХ рдмрдирд╛рдПрдВрдЧреЗ рдЬреЛ рдПрдХреНрд╕реЗрд╕ рдХрд░рддреЗ рд╕рдордп рдУрдХреЗ рд╕реНрдерд┐рддрд┐ рдХреЗ рд╕рд╛рде рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрд░рддрд╛ рд╣реИред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, ./src/shopping-cart/
рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ ./src/shopping-cart/
shoping-cart.controller.ts
:
import { Post, Controller } from '@nestjs/common'; @Controller('shopping-cart') export class ShoppingCartController { @Post() async addItem() { return 'This is a fake service :D'; } }
рдЗрд╕ рдХрдВрдЯреНрд░реЛрд▓рд░ рдХреЛ рд╣рдорд╛рд░реЗ рдореЙрдбреНрдпреВрд▓ рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдХрд░реЗрдВ ( app.module.ts
):
import { Module } from '@nestjs/common'; import { ItemsController } from './items/items.controller'; import { ShoppingCartController } from './shopping-cart/shopping-cart.controller'; import { ItemsService } from './items/items.service'; @Module({ imports: [], controllers: [ItemsController, ShoppingCartController], providers: [ItemsService], }) export class AppModule {}
рдЗрд╕ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдмрд┐рдВрджреБ рдХреЛ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдирд┐рдореНрди рдХрдорд╛рдВрдб рдХреЛ рдЪрд▓рд╛рдПрдВ, рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдХрд┐ рдЖрд╡реЗрджрди рдЪрд▓ рд░рд╣рд╛ рд╣реИ:
curl -X POST localhost:3000/shopping-cart
рдЖрдЗрдЯрдо рдХреЗ рд▓рд┐рдП рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЬреЛрдбрд╝рдирд╛
рд╡рд╛рдкрд╕ рд╣рдорд╛рд░реЗ items
рд╕реЗрд╡рд╛ рдХреЗ рд▓рд┐рдПред рдЕрдм рд╣рдо рдХреЗрд╡рд▓ рдкрдХрд╡рд╛рди рдХреЗ рдирд╛рдо рдХреЛ рдмрдЪрд╛рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реИ, рдФрд░, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рд╣рдо рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдкрдХрд╡рд╛рди рдХреА рд▓рд╛рдЧрдд) рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЖрдк рдЗрд╕ рдмрд╛рдд рд╕реЗ рд╕рд╣рдордд рд╣реЛрдВрдЧреЗ рдХрд┐ рдЗрд╕ рдбреЗрдЯрд╛ рдХреЛ рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдХреА рдПрдХ рд╕рд░рдгреА рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдирд╛ рдПрдХ рдЕрдЪреНрдЫрд╛ рд╡рд┐рдЪрд╛рд░ рдирд╣реАрдВ рд╣реИ?
рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рд╡рд╕реНрддреБрдУрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рд╡рд╕реНрддреБрдУрдВ рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреЛ рдХреИрд╕реЗ рдмрдЪрд╛рдпрд╛ рдЬрд╛рдП? рдпрд╣рд╛рдВ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╣рдорд╛рд░реА рдорджрдж рдХрд░реЗрдЧрд╛, рдЬрд┐рд╕рдореЗрдВ рд╣рдо items
рдСрдмреНрдЬреЗрдХреНрдЯ рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВред src/items
рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ item.interface.ts
рдирд╛рдордХ рдПрдХ рдирдИ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ:
export interface Items { readonly name: string; readonly price: number; }
рдЗрд╕рдХреЗ рдмрд╛рдж items.service.ts
рдлрд╝рд╛рдЗрд▓
import { Injectable } from '@nestjs/common'; import { Item } from './item.interface'; @Injectable() export class ItemsService { private readonly items: Item[] = []; findAll(): Item[] { return this.items; } create(item: Item) { this.items.push(item); } }
рдФрд░ items.controller.ts
рдореЗрдВ рднреАред items.controller.ts
ред items.controller.ts
:
import { Get, Post, Body, Controller } from '@nestjs/common'; import { ItemsService } from './items.service'; import { Item } from './item.interface'; @Controller('items') export class ItemsController { constructor(private readonly itemsService: ItemsService) {} @Get() async findAll(): Promise<Item[]> { return this.itemsService.findAll(); } @Post() async create(@Body() item: Item) { this.itemsService.create(item); } }
Nest.js рдореЗрдВ рдЗрдирдкреБрдЯ рдХрд╛ рд╕рддреНрдпрд╛рдкрди
рдЗрд╕ рддрдереНрдп рдХреЗ рдмрд╛рд╡рдЬреВрдж рдХрд┐ рд╣рдордиреЗ item
рдСрдмреНрдЬреЗрдХреНрдЯ рдХреА рд╕рдВрд░рдЪрдирд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХреА рд╣реИ, рдЕрдЧрд░ рд╣рдо рдПрдХ рдЕрдорд╛рдиреНрдп рдкреЛрд╕реНрдЯ рдЕрдиреБрд░реЛрдз (рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рд╕реА рднреА рдкреНрд░рдХрд╛рд░ рдХрд╛ рдбреЗрдЯрд╛ рдирд╣реАрдВ) рднреЗрдЬрддреЗ рд╣реИрдВ, рддреЛ рд╣рдорд╛рд░рд╛ рдЖрд╡реЗрджрди рдПрдХ рддреНрд░реБрдЯрд┐ рдирд╣реАрдВ рд▓реМрдЯрд╛рдПрдЧрд╛ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЗрд╕ рддрд░рд╣ рдХреЗ рдЕрдиреБрд░реЛрдз рдХреЗ рд▓рд┐рдП:
curl -H 'Content-Type: application/json' -d '{ "name": 3, "price": "any" }' http://localhost:3000/items
рд╕рд░реНрд╡рд░ рдХреЛ 400 (рдЦрд░рд╛рдм рдЕрдиреБрд░реЛрдз) рдХреА рд╕реНрдерд┐рддрд┐ рдХреЗ рд╕рд╛рде рдЬрд╡рд╛рдм рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдП, рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, рд╣рдорд╛рд░рд╛ рдЖрд╡реЗрджрди 200 (рдУрдХреЗ) рдХреА рд╕реНрдерд┐рддрд┐ рдХреЗ рд╕рд╛рде рдЬрд╡рд╛рдм рджреЗрдЧрд╛ред
рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рдбреАрдЯреАрдУ (рдбреЗрдЯрд╛ рдЯреНрд░рд╛рдВрд╕рдлрд░ рдСрдмреНрдЬреЗрдХреНрдЯ) рдФрд░ рдПрдХ рдкрд╛рдЗрдк рдШрдЯрдХ (рдЪреИрдирд▓) рдмрдирд╛рдПрдВред
рдбреАрдЯреАрдУ рдПрдХ рдСрдмреНрдЬреЗрдХреНрдЯ рд╣реИ рдЬреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдбреЗрдЯрд╛ рдХреЛ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЗ рдмреАрдЪ рдХреИрд╕реЗ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рд╣рдо DTO рдХреЛ src/items/create-item.dto.ts
рдореЗрдВ рд╡рд░реНрдгрд┐рдд рдХрд░рддреЗ рд╣реИрдВ:
import { IsString, IsInt } from 'class-validator'; export class CreateItemDto { @IsString() readonly name: string; @IsInt() readonly price: number; }
Nest.js
рдореЗрдВ рдкрд╛рдЗрдк рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдШрдЯрдХ рд╣реИрдВред рд╣рдорд╛рд░реЗ рдПрдкреАрдЖрдИ рдХреЗ рд▓рд┐рдП, рдПрдХ рдЪреИрдирд▓ рдмрдирд╛рдПрдВ рдЬрд┐рд╕рдореЗрдВ рдпрд╣ рдЬрд╛рдВрдЪреЗ рдХрд┐ рд╡рд┐рдзрд┐ рдХреЛ рднреЗрдЬрд╛ рдЧрдпрд╛ рдбреЗрдЯрд╛ рдбреАрдЯреАрдУ рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред рдПрдХ рдЪреИрдирд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рд╡рд┐рднрд┐рдиреНрди рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рджреНрд╡рд╛рд░рд╛ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдлрд╝рд╛рдЗрд▓ validation.pipe.ts
рд╕рд╛рде src/common/
рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдмрдирд╛рдПрдВред
import { ArgumentMetadata, BadRequestException, Injectable, PipeTransform, } from '@nestjs/common'; import { validate } from 'class-validator'; import { plainToClass } from 'class-transformer'; @Injectable() export class ValidationPipe implements PipeTransform<any> { async transform(value, metadata: ArgumentMetadata) { const { metatype } = metadata; if (!metatype || !this.toValidate(metatype)) { return value; } const object = plainToClass(metatype, value); const errors = await validate(object); if (errors.length > 0) { throw new BadRequestException('Validation failed'); } return value; } private toValidate(metatype): boolean { const types = [String, Boolean, Number, Array, Object]; return !types.find(type => metatype === type); } }
рдиреЛрдЯ: рд╣рдореЗрдВ рджреЛ рдореЙрдбреНрдпреВрд▓ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ: class-validator
рдФрд░ class-transformer
ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдХрдВрд╕реЛрд▓ рдореЗрдВ npm install class-validator class-transformer
рдФрд░ рд╕рд░реНрд╡рд░ рдХреЛ рдкреБрдирд░рд╛рд░рдВрдн рдХрд░реЗрдВред
рд╣рдорд╛рд░реЗ рдирдП рдкрд╛рдЗрдк рдФрд░ DTO рдХреЗ рд╕рд╛рде рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП items.controller.ts
рдХреЛ items.controller.ts
:
import { Get, Post, Body, Controller, UsePipes } from '@nestjs/common'; import { CreateItemDto } from './create-item.dto'; import { ItemsService } from './items.service'; import { Item } from './item.interface'; import { ValidationPipe } from '../common/validation.pipe'; @Controller('items') export class ItemsController { constructor(private readonly itemsService: ItemsService) {} @Get() async findAll(): Promise<Item[]> { return this.itemsService.findAll(); } @Post() @UsePipes(new ValidationPipe()) async create(@Body() createItemDto: CreateItemDto) { this.itemsService.create(createItemDto); } }
рдЖрдЗрдП рд╣рдорд╛рд░реЗ рдХреЛрдб рдХреЛ рдлрд┐рд░ рд╕реЗ рдЬрд╛рдВрдЪреЗрдВ, рдЕрдм рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ /items
рдХреЗрд╡рд▓ рдбреЗрдЯрд╛ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддреЗ рд╣реИрдВ рдпрджрд┐ рд╡реЗ рдбреАрдЯреАрдУ рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:
curl -H 'Content-Type: application/json' -d '{ "name": "Salad", "price": 3 }' http://localhost:3000/items
рдЕрдорд╛рдиреНрдп рдбреЗрдЯрд╛ рдореЗрдВ рдЪрд┐рдкрдХрд╛рдПрдБ (рдбреЗрдЯрд╛ рдЬреЛ ValidationPipe
рдореЗрдВ рд╕рддреНрдпрд╛рдкрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ), рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рд╣рдореЗрдВ рдЙрддреНрддрд░ рдорд┐рд▓рддрд╛ рд╣реИ:
{"statusCode":400,"error":"Bad Request","message":"Validation failed"}
рдорд┐рдбрд┐рд▓рд╡реЗрдпрд░ рдмрдирд╛рдирд╛
Auth0 рдХреНрд╡рд┐рдХ рд╕реНрдЯрд╛рд░реНрдЯ рдЧрд╛рдЗрдб рдкреЗрдЬ рдХреЗ рдЕрдиреБрд╕рд╛рд░ , Auth0 рджреНрд╡рд╛рд░рд╛ рдЬрд╛рд░реА JWT рдЯреЛрдХрди рдХреЛ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдиреБрд╢рдВрд╕рд┐рдд рддрд░реАрдХрд╛ express-jwt
рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд╛рди рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реИред рдпрд╣ рдорд┐рдбрд┐рд▓рд╡реЗрдпрд░ рдХрд╛рдо рдХрд╛ рдПрдХ рдмрдбрд╝рд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░рддрд╛ рд╣реИред
рдЖрдЗрдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреЛрдб рдХреЗ рд╕рд╛рде src / common
рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдХреЗ рдЕрдВрджрд░ рдПрдХ authentication.middleware.ts
рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдпреЗрдВ:
import { NestMiddleware } from '@nestjs/common'; import * as jwt from 'express-jwt'; import { expressJwtSecret } from 'jwks-rsa'; export class AuthenticationMiddleware implements NestMiddleware { use(req, res, next) { jwt({ secret: expressJwtSecret({ cache: true, rateLimit: true, jwksRequestsPerMinute: 5, jwksUri: 'https://${DOMAIN}/.well-known/jwks.json', }), audience: 'http://localhost:3000', issuer: 'https://${DOMAIN}/', algorithm: 'RS256', })(req, res, err => { if (err) { const status = err.status || 500; const message = err.message || 'Sorry, we were unable to process your request.'; return res.status(status).send({ message, }); } next(); }); }; }
Auth0 рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕реЗрдЯрд┐рдВрдЧ рд╕реЗ рдбреЛрдореЗрди рдореВрд▓реНрдп рдХреЗ рд╕рд╛рде ${DOMAIN}
рдХреЛ рдмрджрд▓реЗрдВ
рдЕрдиреБрд╡рд╛рджрдХ рдХрд╛ рдзреНрдпрд╛рди рджреЗрдВ: рдПрдХ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ, DOMAIN
рдХреЛ рдПрдХ рд╕реНрдерд┐рд░рд╛рдВрдХ рдореЗрдВ рдмрд╛рд╣рд░ DOMAIN
, рдФрд░ env
(рдЖрднрд╛рд╕реА рд╡рд╛рддрд╛рд╡рд░рдг) рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЗрд╕рдХрд╛ рдорд╛рди рд╕реЗрдЯ рдХрд░реЗрдВ
express-jwt
jwks-rsa
рдФрд░ jwks-rsa
рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ:
npm install express-jwt jwks-rsa
рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП рдмрдирд╛рдП рдЧрдП рдорд┐рдбрд▓рд╡реЗрдпрд░ (рд╣реИрдВрдбрд▓рд░) рдХреЛ рдХрдиреЗрдХреНрдЯ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, ./src/app.module.ts
рдлрд╝рд╛рдЗрд▓ рдореЗрдВ:
import { Module, MiddlewareConsumer, RequestMethod } from '@nestjs/common'; import { AuthenticationMiddleware } from './common/authentication.middleware'; import { ItemsController } from './items/items.controller'; import { ShoppingCartController } from './shopping-cart/shopping-cart.controller'; import { ItemsService } from './items/items.service'; @Module({ imports: [], controllers: [ItemsController, ShoppingCartController], providers: [ItemsService], }) export class AppModule { public configure(consumer: MiddlewareConsumer) { consumer .apply(AuthenticationMiddleware) .forRoutes( { path: '/items', method: RequestMethod.POST }, { path: '/shopping-cart', method: RequestMethod.POST }, ); } }
рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдХрд╛ рдХрд╣рдирд╛ рд╣реИ рдХрд┐ рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдорд┐рдбрд▓рд╡реЗрдпрд░ рджреНрд╡рд╛рд░рд╛ /items
рдФрд░ /shopping-cart
рдорд╛рд░реНрдЧреЛрдВ рдХреЗ рд▓рд┐рдП POST рдЕрдиреБрд░реЛрдз рд╕реБрд░рдХреНрд╖рд┐рдд рд╣реИрдВ, рдЬреЛ рдЕрдиреБрд░реЛрдз рдореЗрдВ рдкрд╣реБрдБрдЪ рдЯреЛрдХрди рдХреЗ рд▓рд┐рдП рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИред
рд╡рд┐рдХрд╛рд╕ рд╕рд░реНрд╡рд░ рдХреЛ рдкреБрдирдГ рдЖрд░рдВрдн рдХрд░реЗрдВ ( npm run start:dev
) рдФрд░ Nest.js API рдкрд░ рдХреЙрд▓ рдХрд░реЗрдВ:
Auth0 рдХреЗ рд╕рд╛рде рднреВрдорд┐рдХрд╛ рдкреНрд░рдмрдВрдзрди
рдлрд┐рд▓рд╣рд╛рд▓, рд╕рддреНрдпрд╛рдкрд┐рдд рдЯреЛрдХрди рд╡рд╛рд▓рд╛ рдХреЛрдИ рднреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╣рдорд╛рд░реЗ рдПрдкреАрдЖрдИ рдореЗрдВ рдЖрдЗрдЯрдо рдкреЛрд╕реНрдЯ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, рд╣рдо рдЪрд╛рд╣реЗрдВрдЧреЗ рдХрд┐ рдХреЗрд╡рд▓ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдЕрдзрд┐рдХрд╛рд░реЛрдВ рд╡рд╛рд▓реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╣реА рдРрд╕рд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдирд┐рдпрдореЛрдВ (рдирд┐рдпрдореЛрдВ) Auth0 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ ред
рддреЛ, рдирд┐рдпрдо рдЕрдиреБрднрд╛рдЧ рдореЗрдВ, Auth0 рдирд┐рдпрдВрддреНрд░рдг рдХрдХреНрд╖ рдкрд░ рдЬрд╛рдПрдВред рд╡рд╣рд╛рдВ, + CREATE RULE
рдФрд░ рдирд┐рдпрдо рдореЙрдбрд▓ рдХреЗ рд░реВрдк рдореЗрдВ "рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рднреВрдорд┐рдХрд╛рдПрдВ рд╕реЗрдЯ рдХрд░реЗрдВ" рдЪреБрдиреЗрдВред

рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдореЗрдВ рдПрдХ рдирд┐рдпрдо рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЗ рд╕рд╛рде рдПрдХ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдлрд╝рд╛рдЗрд▓ рдорд┐рд▓рддреА рд╣реИ рдЬреЛ рдХрд┐рд╕реА рднреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рднреВрдорд┐рдХрд╛ рдЬреЛрдбрд╝рддреА рд╣реИ рдЬрд┐рд╕рдХреЗ рдкрд╛рд╕ рдПрдХ рдИрдореЗрд▓ рд╣реИ рдЬреЛ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдбреЛрдореЗрди рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реИред рдЪрд▓рд┐рдП рдЗрд╕ рдЯреЗрдореНрдкрд▓реЗрдЯ рдореЗрдВ рдХреБрдЫ рд╡рд┐рд╡рд░рдг рдмрджрд▓рдХрд░ рдПрдХ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдЙрджрд╛рд╣рд░рдг рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП, рд╣рдо рдХреЗрд╡рд▓ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдИрдореЗрд▓ рдкрддреЗ рдкрд░ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдХреЛ рдкрд╣реБрдВрдЪ рдкреНрд░рджрд╛рди рдХрд░реЗрдВрдЧреЗред рд╣рдореЗрдВ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рд╕реНрдерд┐рддрд┐ рдЬрд╛рдирдХрд╛рд░реА рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдерд╛рди рдмрджрд▓рдиреЗ рдХреА рднреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред
рдлрд┐рд▓рд╣рд╛рд▓, рдпрд╣ рдЬрд╛рдирдХрд╛рд░реА рдПрдХ рдкрд╣рдЪрд╛рди рдЯреЛрдХрди (рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛рддреА рд╣реИ) рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реИ, рд▓реЗрдХрд┐рди рдПрдкреАрдЖрдИ рдореЗрдВ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдПрдХреНрд╕реЗрд╕ рдЯреЛрдХрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рдмрд╛рдж рдХрд╛ рдХреЛрдб рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП:
function (user, context, callback) { user.app_metadata = user.app_metadata || {}; if (user.email && user.email === '${YOUR_EMAIL}') { user.app_metadata.roles = ['admin']; } else { user.app_metadata.roles = ['user']; } auth0.users .updateAppMetadata(user.user_id, user.app_metadata) .then(function() { context.accessToken['http://localhost:3000/roles'] = user.app_metadata.roles; callback(null, user, context); }) .catch(function(err) { callback(err); }); }
рдиреЛрдЯ: ${YOUR_EMAIL}
рдХреЛ рдЕрдкрдиреЗ рдИрдореЗрд▓ рдкрддреЗ рд╕реЗ рдмрджрд▓реЗрдВред рдпрд╣ рдиреЛрдЯ рдХрд░рдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рдХрд┐, рдПрдХ рдирд┐рдпрдо рдХреЗ рд░реВрдк рдореЗрдВ, рдЬрдм рдЖрдк Auth0 рдирд┐рдпрдореЛрдВ рдореЗрдВ рдИрдореЗрд▓ рд╕реЗ рдирд┐рдкрдЯрддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрджрд░реНрд╢ рд╣реИред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдИрдореЗрд▓ рдкрддреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред
рдЕрдиреБрд╡рд╛рджрдХ рдХрд╛ рдиреЛрдЯ: рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдЯреБрдХрдбрд╝рд╛ рдХреЛ Auth0 рдирд┐рдпрдо рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдкреГрд╖реНрда рдкрд░ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рджрд░реНрдЬ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ
рдпрд╣ рдЬрд╛рдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рд╣рдорд╛рд░реЗ рдПрдкреАрдЖрдИ рдореЗрдВ рдЯреЛрдХрди рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВ, рд╣рдореЗрдВ рдЯреЛрдХрди рдХреА рдЬрд░реВрд░рдд рд╣реИ, рд╣рдореЗрдВ рдПрдХ рдЧрд╛рд░реНрдб Nest.js. src/common
рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ, admin.guard.ts
рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; @Injectable() export class AdminGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const user = context.getArgs()[0].user['http://localhost:3000/roles'] || ''; return user.indexOf('admin') > -1; } }
рдЕрдм, рдпрджрд┐ рд╣рдо рдКрдкрд░ рд╡рд░реНрдгрд┐рдд рд▓реЙрдЧрд┐рди рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рджреЛрд╣рд░рд╛рддреЗ рд╣реИрдВ рдФрд░ рдирд┐рдпрдо рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдИрдореЗрд▓ рдкрддреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ рдПрдХ рдирдпрд╛ access_token
ред рдЗрд╕ access_token
рдХреА рд╕рд╛рдордЧреНрд░реА рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╕рд╛рдЗрдЯ https://jwt.io/
рдХреЗ Encoded
рдлрд╝реАрд▓реНрдб рдореЗрдВ рдЯреЛрдХрди рдХреЛ рдХреЙрдкреА рдФрд░ рдкреЗрд╕реНрдЯ https://jwt.io/
ред рд╣рдо рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ рдЗрд╕ рдЯреЛрдХрди рдХреЗ рдкреЗрд▓реЛрдб рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рд░рдгреА рд╣реИрдВ:
"http://localhost:3000/roles": [ "admin" ]
рдпрджрд┐ рд╣рдорд╛рд░реЗ рдЯреЛрдХрди рдореЗрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣ рдЬрд╛рдирдХрд╛рд░реА рд╢рд╛рдорд┐рд▓ рд╣реИ, рддреЛ рд╣рдо Auth0 рдХреЗ рд╕рд╛рде рдПрдХреАрдХрд░рдг рдЬрд╛рд░реА рд░рдЦрддреЗ рд╣реИрдВред рддреЛ, items.controller.ts
рдЦреЛрд▓реЗрдВ items.controller.ts
рдФрд░ рд╡рд╣рд╛рдВ рд╣рдорд╛рд░рд╛ рдирдпрд╛ рдЧрд╛рд░реНрдб рдЬреЛрдбрд╝реЗрдВ:
import { Get, Post, Body, Controller, UsePipes, UseGuards, } from '@nestjs/common'; import { CreateItemDto } from './create-item.dto'; import { ItemsService } from './items.service'; import { Item } from './item.interface'; import { ValidationPipe } from '../common/validation.pipe'; import { AdminGuard } from '../common/admin.guard'; @Controller('items') export class ItemsController { constructor(private readonly itemsService: ItemsService) {} @Get() async findAll(): Promise<Item[]> { return this.itemsService.findAll(); } @Post() @UseGuards(new AdminGuard()) @UsePipes(new ValidationPipe()) async create(@Body() createItemDto: CreateItemDto) { this.itemsService.create(createItemDto); } }
рдЕрдм, рд╣рдорд╛рд░реЗ рдирдП рдЯреЛрдХрди рдХреЗ рд╕рд╛рде, рд╣рдо рдЕрдкрдиреЗ рдПрдкреАрдЖрдИ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдирдП рдЖрдЗрдЯрдо рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ:
рдЕрдиреБрд╡рд╛рджрдХ рдХрд╛ рдиреЛрдЯ: рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП, рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреНрдпрд╛ рд╣реИ:
curl -X GET http://localhost:3000/items
рдкрд░рд┐рдгрд╛рдо
рдмрдзрд╛рдИ! рд╣рдордиреЗ рдЕрднреА рдЕрдкрдирд╛ Nest.JS API рдмрдирд╛рдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛ рдФрд░ рдЕрдм рд╣рдо рдЕрдкрдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдлреНрд░рдВрдЯреЗрдВрдб рднрд╛рдЧ рдХреЛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рдкрд░ рдзреНрдпрд╛рди рдХреЗрдВрджреНрд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ! рдЗрд╕ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХреЗ рджреВрд╕рд░реЗ рднрд╛рдЧ рдХреЛ рджреЗрдЦрдирд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ: рдлреБрд▓-рд╕реНрдЯреИрдХ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдРрдкреНрд╕ - рднрд╛рдЧ 2: рдлреНрд░рдВрдЯрд┐рдВрдЧ рдХреЛрдгреАрдп рдХреЛрдгреАрдп рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдирд╛ред
рдЕрдиреБрд╡рд╛рджрдХ рдХрд╛ рдиреЛрдЯ: рджреВрд╕рд░реЗ рднрд╛рдЧ рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдЬрд╛рд░реА рд╣реИред
рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ, рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рд╣рдордиреЗ Nest.js рдФрд░ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреА рд╡рд┐рднрд┐рдиреНрди рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛: рдореЙрдбреНрдпреВрд▓, рдирд┐рдпрдВрддреНрд░рдХ, рд╕реЗрд╡рд╛рдПрдВ, рдЗрдВрдЯрд░рдлреЗрд╕, рдкрд╛рдЗрдк, рдорд┐рдбрд▓рд╡реЗрдпрд░ рдФрд░ рдЧрд╛рд░реНрдб рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдкреАрдЖрдИред рдореБрдЭреЗ рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдПрдХ рдЕрдЪреНрдЫрд╛ рдЕрдиреБрднрд╡ рд╣реИ рдФрд░ рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреЛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд╛рд░реА рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВред рдпрджрд┐ рдЖрдкрдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИ, рддреЛ рдЖрдзрд┐рдХрд╛рд░рд┐рдХ n.js рдкреНрд░рд▓реЗрдЦрди рдЙрддреНрддрд░ рдХреЗ рд╕рд╛рде рдПрдХ рдЕрдЪреНрдЫрд╛ рд╕реНрд░реЛрдд рд╣реИ