{"id":361434,"date":"2024-05-21T01:13:34","date_gmt":"2024-05-21T01:13:34","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=361434"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-05-21T01:13:34","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=361434","title":{"rendered":"<span>\u042d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u0434\u0435\u043f\u043b\u043e\u0439 gRPC API \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e GitHub Actions \u0438 Packages \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 Kotlin \u0438 React<\/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-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u044d\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0435 \u044f \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e GitHub Actions \u043b\u0435\u0433\u043a\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044e gRPC API \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0432 GitHub Packages, \u0432 \u0440\u0435\u0435\u0441\u0442\u0440\u0430\u0445 Apache Maven \u0438 npm. \u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043e\u0441\u0432\u043e\u0438\u0442\u044c GitHub Packages \u0434\u043b\u044f \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0438 \u043d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c gRPC API \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430 Kotlin\/Java \u0438 gRPC-web \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u2014 \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/325\/7e2\/2f5\/3257e22f539348ec07a56c0212ec8b77.jpg\" width=\"1792\" height=\"1024\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/325\/7e2\/2f5\/3257e22f539348ec07a56c0212ec8b77.jpg\" data-blurred=\"true\"\/><\/figure>\n<h3>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0412\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u043a \u0434\u043e\u043a\u043b\u0430\u0434\u0443 <a href=\"https:\/\/habr.com\/ru\/companies\/rosbank\/articles\/743536\/\"><u>JPoint<\/u><\/a> \u0443 \u043c\u0435\u043d\u044f \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u0438\u0434\u0435\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0441\u0442\u0435\u043d\u0434, \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0438\u0439 \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442 \u0438 \u0431\u044d\u043a\u0435\u043d\u0434-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u042d\u0442\u043e\u0442 \u0441\u0442\u0435\u043d\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b \u0431\u044b \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0439 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f SQL-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441 \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u0435\u0439. \u0414\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0438 \u0431\u044d\u043a\u0435\u043d\u0434\u043e\u043c \u044f \u0440\u0435\u0448\u0438\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c gRPC. \u041c\u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439 \u0442\u0430\u043a\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u0438 \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f gRPC API \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e GitHub Actions \u0438 GitHub Packages. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u044d\u0442\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c \u0441 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u0425\u0430\u0431\u0440\u0430.<\/p>\n<h3>\u0412\u044b\u0431\u043e\u0440 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u0442\u0435\u043a\u0430 \u0438 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438<\/h3>\n<p>\u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b Kotlin, \u043e\u0434\u043d\u0430\u043a\u043e \u0432\u0441\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0434\u043b\u044f Java.<\/p>\n<p>\u042f \u0432\u044b\u0431\u0440\u0430\u043b Spring \u0438 Kotlin \u0434\u043b\u044f \u0431\u044d\u043a\u0435\u043d\u0434\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 React \u0441 TypeScript \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u0447\u0442\u043e \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u043b\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0443\u0436\u043d\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430. \u0412\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f gRPC \u2014 \u044d\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a Google, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b (RPC) \u043c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f Protocol Buffers \u043a\u0430\u043a \u044f\u0437\u044b\u043a \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430. gRPC \u0438\u043c\u0435\u0435\u0442 \u0440\u044f\u0434 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432:<\/p>\n<ul>\n<li>\n<p>\u0432\u044b\u0441\u043e\u043a\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 HTTP\/2;<\/p>\n<\/li>\n<li>\n<p>\u0441\u0442\u0440\u043e\u0433\u0430\u044f \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u044f Protocol Buffers, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0434\u0438\u0437\u0430\u0439\u043d\u0430 API \u0438 \u0441\u043d\u0438\u0436\u0430\u0435\u0442 \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043e\u043a \u043f\u0440\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432;<\/p>\n<\/li>\n<li>\n<p>.proto \u0444\u0430\u0439\u043b\u044b \u0441 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 API \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432 \u043a\u043e\u0434 \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u044f\u0437\u044b\u043a\u043e\u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0439 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b <a href=\"https:\/\/github.com\/grpc\/grpc-web\"><u>gRPC-web<\/u><\/a>, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 gRPC. gRPC-web \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u043e\u0431\u044b\u0447\u043d\u044b\u043c\u0438 gRPC-\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438 \u0438\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. \u041f\u043e\u043a\u0430 \u0447\u0442\u043e gRPC-web \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0432\u0430 \u0440\u0435\u0436\u0438\u043c\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f: \u0443\u043d\u0430\u0440\u043d\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u0438 server-side \u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433.<\/p>\n<h3>\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f<\/h3>\n<p>\u041c\u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u044b\u043c \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 gRPC API \u043f\u0430\u043a\u0435\u0442\u044b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/github.com\/features\/actions\"><u>GitHub Actions<\/u><\/a> \u0438 <a href=\"https:\/\/github.com\/features\/packages\"><u>GitHub Packages<\/u><\/a>. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0442\u043d\u0443\u044e \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 API \u0438 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c\u0443 style guide \u043e\u0442 Google \u0434\u043b\u044f .proto \u0444\u0430\u0439\u043b\u043e\u0432, \u044f \u0432\u043d\u0435\u0434\u0440\u0438\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/github.com\/nilslice\/protolock\"><u>protolock<\/u><\/a> \u0438 <a href=\"https:\/\/github.com\/yoheimuta\/protolint\"><u>protolint<\/u><\/a>.<\/p>\n<h3>\u041e \u0432\u044b\u0431\u043e\u0440\u0435 GitHub Packages<\/h3>\n<p>\u041f\u0440\u0438\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f GitHub Packages \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e \u0441 GitHub Actions, \u043f\u043e \u043c\u043e\u0435\u043c\u0443 \u043c\u043d\u0435\u043d\u0438\u044e, \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c:<\/p>\n<ul>\n<li>\n<p>\u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438 \u0434\u0435\u043f\u043b\u043e\u044f \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0432 GitHub Packages \u0432 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 \u0441 Maven Central;<\/p>\n<\/li>\n<li>\n<p>\u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u0441\u0435\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\u043a\u043e\u0434, CI\/CD \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u044b, \u043f\u0430\u043a\u0435\u0442\u044b) \u043d\u0430 GitHub, \u0447\u0442\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p>\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 \u0442\u0430\u0440\u0438\u0444, \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0438\u0439 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432 \u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u0445 \u0434\u0435\u043f\u043b\u043e\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u0441\u0435 \u044d\u0442\u0438 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0434\u0435\u043b\u0430\u044e\u0442 GitHub Actions \u0438 Packages \u0445\u043e\u0440\u043e\u0448\u0438\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0434\u043b\u044f Pet-\u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432. \u0422\u0435\u043c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435 \u0435\u0441\u0442\u044c \u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a: \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 Maven Central, \u0434\u043b\u044f \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f GitHub-\u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0438 \u0442\u043e\u043a\u0435\u043d \u0441 \u043f\u0440\u0430\u0432\u0430\u043c\u0438 \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u0435 \u043f\u0430\u043a\u0435\u0442\u043e\u0432. \u041a\u0430\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0442\u043e\u043a\u0435\u043d, \u044f \u043e\u043f\u0438\u0448\u0443 \u043d\u0438\u0436\u0435.\u00a0<\/p>\n<h3>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h3>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c Gradle-\u043f\u0440\u043e\u0435\u043a\u0442 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Kotlin DSL \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c .proto \u0444\u0430\u0439\u043b\u044b.<\/p>\n<p>Proto-\u0444\u0430\u0439\u043b API \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<pre><code class=\"kotlin\">syntax = \"proto3\";  package com.arvgord.api.grpc.bankdemo.v1;  import \"bankdemo\/v1\/messages\/client_list_item.proto\"; import \"bankdemo\/v1\/messages\/extracting_strategy.proto\"; import \"bankdemo\/v1\/messages\/page_request.proto\"; import \"google\/protobuf\/wrappers.proto\";  \/\/ Get client list request message GetClientListRequest {  \/\/ Current page  PageRequest page_request = 1;  \/\/ Extracting strategy  ExtractingStrategy extracting_strategy = 2; }  \/\/ Get client list response message GetClientListResponse {  \/\/ Clients  repeated ClientListItem clients = 1;  \/\/ Total number of clients  google.protobuf.Int64Value total_clients = 2;  \/\/ Total number of pages  google.protobuf.Int32Value total_pages = 3; }  \/\/ Service BankDemo service BankDemo {  \/\/ Get client list  rpc GetClientList(GetClientListRequest) returns (GetClientListResponse); }<\/code><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 .proto \u0444\u0430\u0439\u043b\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f PageRequest:<\/p>\n<pre><code class=\"kotlin\">syntax = \"proto3\";  package com.arvgord.api.grpc.bankdemo.v1;  import \"google\/protobuf\/wrappers.proto\";  \/\/ Page message PageRequest {  \/\/ Number of clients on page  google.protobuf.Int32Value page = 1;  \/\/ Page size  google.protobuf.Int32Value size = 2; }<\/code><\/pre>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h4>\n<p>\u0414\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432 \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043a\u043e\u0440\u0435\u043d\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0444\u0430\u0439\u043b gradle.properties \u0441 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439:<\/p>\n<pre><code class=\"kotlin\">kotlinVersion=1.9.10 protobufPluginVersion=0.9.4 protobufKotlinVersion=3.24.4 grpcProtobufVersion=1.58.0 grpcKotlinVersion=1.4.0<\/code><\/pre>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u0444\u0430\u0439\u043b settings.gradle.kts, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0443\u043a\u0430\u0436\u0435\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<pre><code class=\"kotlin\">rootProject.name = \"bank-demo-api\"<\/code><\/pre>\n<p>\u0410 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043c\u0435\u043d\u0435\u0434\u0436\u043c\u0435\u043d\u0442 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432:<\/p>\n<pre><code class=\"kotlin\">pluginManagement {    val kotlinVersion: String by settings    val protobufPluginVersion: String by settings    plugins {        kotlin(\"jvm\") version kotlinVersion        id(\"com.google.protobuf\") version protobufPluginVersion    }    repositories {        gradlePluginPortal()    } }<\/code><\/pre>\n<p>\u0412\u0435\u0440\u0441\u0438\u0438 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u0432 settings.gradle.kts \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u0432 gradle.properties, \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 build.gradle.kts. \u0427\u0442\u043e \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0445 \u0432\u0440\u0443\u0447\u043d\u0443\u044e.<\/p>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u0444\u0430\u0439\u043b build.gradle.kts. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u043b\u0430\u0433\u0438\u043d\u044b:<\/p>\n<pre><code class=\"kotlin\">plugins {    kotlin(\"jvm\")    id(\"com.google.protobuf\")    id(\"maven-publish\") }<\/code><\/pre>\n<p>\u042d\u0442\u0438 \u043f\u043b\u0430\u0433\u0438\u043d\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0434\u043b\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, .proto \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0432 Apache Maven registry GitHub.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0433\u0440\u0443\u043f\u043f\u0443 \u0438 \u0432\u0435\u0440\u0441\u0438\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 API, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442\u0430:<\/p>\n<pre><code class=\"kotlin\">group = \"com.arvgord\" version = \"0.0.1\"<\/code><\/pre>\n<p>\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 name \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u0437\u044f\u0442\u043e \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 settings.gradle.kts. \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u0441\u043b\u0435 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a: <code>com.arvgord:bank-demo-api:0.0.1<\/code>.<\/p>\n<p>\u0423\u043a\u0430\u0436\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 gRPC \u0438 Protocol Buffers \u0434\u043b\u044f Kotlin:<\/p>\n<pre><code class=\"kotlin\">dependencies {    implementation(\"io.grpc:grpc-kotlin-stub:${property(\"grpcKotlinVersion\")}\")    implementation(\"io.grpc:grpc-protobuf:${property(\"grpcProtobufVersion\")}\")    implementation(\"com.google.protobuf:protobuf-kotlin:${property(\"protobufKotlinVersion\")}\") }<\/code><\/pre>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 protobuf \u043f\u043b\u0430\u0433\u0438\u043d\u0430<\/h4>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043f\u043b\u0430\u0433\u0438\u043d protobuf, \u0447\u0442\u043e\u0431\u044b \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 .proto \u0444\u0430\u0439\u043b\u043e\u0432:<\/p>\n<pre><code class=\"kotlin\">protobuf {    protoc {        artifact = \"com.google.protobuf:protoc:${property(\"protobufKotlinVersion\")}\"    }    plugins {        id(\"grpc\") {            artifact = \"io.grpc:protoc-gen-grpc-java:${property(\"grpcProtobufVersion\")}\"        }        id(\"grpckt\") {            artifact = \"io.grpc:protoc-gen-grpc-kotlin:${property(\"grpcKotlinVersion\")}:jdk8@jar\"        }        id(\"protoc-gen-js\") {            path = projectDir.path.plus(\"\/tools\/protoc-gen-js-3.21.2-linux-x86_64\")        }        id(\"protoc-gen-grpc-web\") {            path = projectDir.path.plus(\"\/tools\/protoc-gen-grpc-web-1.4.2-linux-x86_64\")        }    }    generateProtoTasks {        all().forEach {            it.plugins {                id(\"grpc\")                id(\"grpckt\")                id(\"protoc-gen-js\") {                    option(\"import_style=commonjs,binary\")                }                id(\"protoc-gen-grpc-web\") {                    option(\"import_style=commonjs+dts,mode=grpcweb\")                }            }            it.builtins {                id(\"kotlin\")            }        }    } }<\/code><\/pre>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0441\u0435\u043a\u0446\u0438\u044e plugins:\u00a0<\/p>\n<ul>\n<li>\n<p>\u041f\u043b\u0430\u0433\u0438\u043d\u044b grpc \u0438 grpckt \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 Java-\u043a\u043e\u0434\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0433\u043e \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438\/\u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0433\u043e \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0433\u043e gRPC \u043a\u043e\u0434\u0430 \u043d\u0430 Kotlin.\u00a0<\/p>\n<\/li>\n<li>\n<p>\u041f\u043b\u0430\u0433\u0438\u043d <a href=\"https:\/\/github.com\/protocolbuffers\/protobuf-javascript\"><u>protoc-gen-js<\/u><\/a> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 JavaScript \u043a\u043e\u0434\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 .proto \u0444\u0430\u0439\u043b\u043e\u0432 \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438\/\u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e <a href=\"https:\/\/github.com\/protocolbuffers\/protobuf-javascript\/releases\"><u>\u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c<\/u><\/a> \u043f\u043b\u0430\u0433\u0438\u043d \u0438 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0435\u0433\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043b\u0430\u0433\u0438\u043d <a href=\"https:\/\/github.com\/grpc\/grpc-web\"><u>protoc-gen-grpc-web<\/u><\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 gRPC-\u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0438\u0437 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u042d\u0442\u043e\u0442 \u043f\u043b\u0430\u0433\u0438\u043d \u0442\u0430\u043a\u0436\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e <a href=\"https:\/\/github.com\/grpc\/grpc-web\/releases\"><u>\u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c<\/u><\/a> \u0438 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0443\u0442\u044c \u043a \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044e.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0441\u0435\u043a\u0446\u0438\u0438 generateProtoTasks \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0437\u0430\u0434\u0430\u0447\u0438 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u0434\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 .proto \u0444\u0430\u0439\u043b\u043e\u0432. protoc-gen-grpc-web \u043f\u043b\u0430\u0433\u0438\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a JS, \u0442\u0430\u043a \u0438 TypeScript \u043a\u043e\u0434. \u0422\u0430\u043a \u043a\u0430\u043a \u043c\u043d\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u044b\u043b\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c TypeScript \u043a\u043e\u0434 \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 gRPC \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0432 options protoc-gen-js \u0438 protoc-gen-grpc-web, \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 <code>import_style=commonjs,binary \u0438 import_style=commonjs+dts,mode=grpcweb<\/code>. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 <a href=\"https:\/\/github.com\/grpc\/grpc-web#import-style\"><u>\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438<\/u><\/a>.<\/p>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 Maven-\u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0430<\/h4>\n<p>\u0424\u0430\u0439\u043b build.gradle.kts \u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438:<\/p>\n<pre><code class=\"kotlin\">publishing {    repositories {        maven {            name = \"GitHubPackages\"            url = uri(\"https:\/\/maven.pkg.github.com\/arvgord\/bank-demo-api\")            credentials {                username = System.getenv(\"GITHUB_ACTOR\")                password = System.getenv(\"GITHUB_TOKEN\")            }        }    }    publications {        create&lt;MavenPublication>(\"maven\") {            from(components[\"kotlin\"])        }    } }<\/code><\/pre>\n<p>\u0412 URL \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f (<a href=\"https:\/\/maven.pkg.github.com\/OWNER\/REPOSITORY\">https:\/\/maven.pkg.github.com\/OWNER\/REPOSITORY<\/a>), \u043a\u0443\u0434\u0430 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u043a\u0435\u0442, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c OWNER \u043d\u0430 \u0438\u043c\u044f \u0432\u0430\u0448\u0435\u0433\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 \u043d\u0430 GitHub \u0438 REPOSITORY \u043d\u0430 \u0438\u043c\u044f \u0432\u0430\u0448\u0435\u0433\u043e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 username \u0438 password \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u0440\u0435\u0434\u044b GITHUB_ACTOR \u0438 GITHUB_TOKEN. \u041e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0432 GitHub Actions.<\/p>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 npm-\u043f\u0430\u043a\u0435\u0442\u0430<\/h4>\n<p>\u0414\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 npm-\u043f\u0430\u043a\u0435\u0442\u0430 \u044f \u0440\u0435\u0448\u0438\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e npm_package \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0443\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b package.json \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438. \u0412 build.gradle.kts \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0443 \u0434\u043b\u044f \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 TypeScript \u0438 JS \u0444\u0430\u0439\u043b\u043e\u0432 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e npm_package:<\/p>\n<pre><code class=\"kotlin\">tasks.register&lt;Copy>(\"buildAndCopy\") {    from(        projectDir.path.plus(\"\/build\/generated\/source\/proto\/main\/protoc-gen-js\"),        projectDir.path.plus(\"\/build\/generated\/source\/proto\/main\/protoc-gen-grpc-web\")    )    into(projectDir.path.plus(\"\/npm_package\/\")) }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0444\u0430\u0439\u043b\u0430 package.json, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0435\u0433\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 npm-\u043f\u0430\u043a\u0435\u0442\u0430:<\/p>\n<pre><code class=\"json\">{  \"name\": \"@arvgord\/bank-demo-api\",  \"version\": \"0.0.1\",  \"description\": \"Generated typescript files for gRPC-web bank-demo-client application\",  \"repository\": {    \"type\": \"git\",    \"url\": \"https:\/\/github.com\/arvgord\/bank-demo-api.git\"  },  \"dependencies\": {    \"grpc-web\": \"^1.4.2\",    \"google-protobuf\": \"^3.21.2\"  } }<\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0444\u0430\u0439\u043b\u0435:<\/p>\n<ul>\n<li>\n<p>name \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0438\u043c\u0435\u043d \u0438 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0438\u043c\u044f \u043f\u0430\u043a\u0435\u0442\u0430;<\/p>\n<\/li>\n<li>\n<p>version \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043f\u0430\u043a\u0435\u0442\u0430;<\/p>\n<\/li>\n<li>\n<p>description \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u0440\u0430\u0442\u043a\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0438 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u0430\u043a\u0435\u0442\u0430;<\/p>\n<\/li>\n<li>\n<p>repository \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u043f\u0430\u043a\u0435\u0442\u0430;<\/p>\n<\/li>\n<li>\n<p>dependencies \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0430\u043a\u0435\u0442\u0430.<\/p>\n<\/li>\n<\/ul>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Action \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u0432 GitHub Packages<\/h4>\n<p>\u0414\u043b\u044f \u0444\u0430\u0439\u043b\u043e\u0432 GitHub Actions \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 .github\/workflows.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 publish_packages.yml \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 .github\/workflows:<\/p>\n<pre><code class=\"yaml\">name: Publish bank-demo-api packages on:   workflow_dispatch:  jobs:  publish:    runs-on: ubuntu-latest    steps:      - uses: actions\/checkout@v4      - uses: actions\/setup-java@v3        with:          java-version: '8'          distribution: 'corretto'      - name: Build packages        run: .\/gradlew buildAndCopy      - name: Publish Kotlin gRPC API        run: .\/gradlew publish        env:          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}      - uses: actions\/setup-node@v3        with:          node-version: '20.x'          registry-url: 'https:\/\/npm.pkg.github.com'          scope: '@arvgord'      - name: Publish bank-demo-client gRPC API        run: |          cd .\/npm_package          npm i          npm publish        env:          NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}<\/code><\/pre>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u044d\u0442\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430:<\/p>\n<ul>\n<li>\n<p>workflow_dispatch: \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c workflow \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 GitHub \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 Actions.<\/p>\n<\/li>\n<li>\n<p>actions\/checkout@v4: \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>setup-java@v3: \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 Java 8 \u0432\u0435\u0440\u0441\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>.\/gradlew buildAndCopy: \u0441\u0431\u043e\u0440\u043a\u0430 \u043f\u0430\u043a\u0435\u0442\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>.\/gradlew publish: \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f Kotlin \u043f\u0430\u043a\u0435\u0442\u0430 \u0432 GitHub Apache Maven registry. \u0414\u043b\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f GITHUB_TOKEN. GITHUB_ACTOR \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 build.gradle.kts \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0442.\u043a. \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <a href=\"https:\/\/docs.github.com\/en\/actions\/learn-github-actions\/variables#default-environment-variables\"><u>\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/u><\/a>.<\/p>\n<\/li>\n<li>\n<p>actions\/setup-node@v3: \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f Node.js \u0432\u0435\u0440\u0441\u0438\u0438 20.x \u0434\u043b\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 npm \u043f\u0430\u043a\u0435\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>Publish bank-demo-client gRPC API: \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e npm_package, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f npm-\u043f\u0430\u043a\u0435\u0442\u0430 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c NODE_AUTH_TOKEN.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0445 \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0434\u043d\u044f\u0442\u044c \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c\u044b\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043e\u0448\u0438\u0431\u043e\u043a \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u0430 \u0438\u0445 \u0432\u0435\u0440\u0441\u0438\u0439:<\/p>\n<ol>\n<li>\n<p>\u0412 \u0444\u0430\u0439\u043b\u0435 build.gradle.kts \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <em>version<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0444\u0430\u0439\u043b\u0435 package.json \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>version<\/code>.<\/p>\n<\/li>\n<\/ol>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e15\/00f\/3a0\/e1500f3a0cbb32454792a90dcaa0a36d.png\" alt=\"\u0420\u0443\u0447\u043d\u043e\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442\u0430 \u0438\u0437 \u0440\u0430\u0437\u0434\u0435\u043b\u0430 Actions\" title=\"\u0420\u0443\u0447\u043d\u043e\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442\u0430 \u0438\u0437 \u0440\u0430\u0437\u0434\u0435\u043b\u0430 Actions\" width=\"1199\" height=\"461\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e15\/00f\/3a0\/e1500f3a0cbb32454792a90dcaa0a36d.png\"\/><\/p>\n<div><figcaption><em>\u0420\u0443\u0447\u043d\u043e\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442\u0430 \u0438\u0437 \u0440\u0430\u0437\u0434\u0435\u043b\u0430 Actions<\/em><\/figcaption><\/div>\n<\/figure>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/035\/117\/132\/0351171326a8c85a05ff68316a69f64f.png\" alt=\"\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0441\u0431\u043e\u0440\u043a\u0438 \u043d\u043e\u0432\u044b\u0435 \u043f\u0430\u043a\u0435\u0442\u044b \u043f\u043e\u044f\u0432\u044f\u0442\u0441\u044f \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 Packages\" title=\"\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0441\u0431\u043e\u0440\u043a\u0438 \u043d\u043e\u0432\u044b\u0435 \u043f\u0430\u043a\u0435\u0442\u044b \u043f\u043e\u044f\u0432\u044f\u0442\u0441\u044f \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 Packages\" width=\"274\" height=\"115\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/035\/117\/132\/0351171326a8c85a05ff68316a69f64f.png\"\/><\/p>\n<div><figcaption><em>\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0441\u0431\u043e\u0440\u043a\u0438 \u043d\u043e\u0432\u044b\u0435 \u043f\u0430\u043a\u0435\u0442\u044b \u043f\u043e\u044f\u0432\u044f\u0442\u0441\u044f \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 Packages<\/em><\/figcaption><\/div>\n<\/figure>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u043e\u043a\u0441\u0438<\/h4>\n<p>\u0412 \u0441\u0430\u043c\u043e\u043c \u043d\u0430\u0447\u0430\u043b\u0435 \u044f \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043b \u043e \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438: gRPC-web \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u043d\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u044b \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u043e\u0431\u044b\u0447\u043d\u044b\u043c\u0438 gRPC-\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438. \u0427\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435, \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435. \u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u044f \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e <a href=\"https:\/\/github.com\/envoyproxy\/envoy\"><u>envoy<\/u><\/a> \u043f\u0440\u043e\u043a\u0441\u0438. \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0431\u044b\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <a href=\"https:\/\/github.com\/grpc\/grpc-web\/blob\/master\/net\/grpc\/gateway\/examples\/echo\/envoy.yaml\"><u>\u043f\u0440\u0438\u043c\u0435\u0440\u0430<\/u><\/a>, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0433\u043e \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 gRPC-web \u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"yaml\">admin:  access_log_path: \/tmp\/admin_access.log  address:    socket_address: { address: 0.0.0.0, port_value: 9901 }   static_resources:  listeners:    - name: listener_0      address:        socket_address: { address: 0.0.0.0, port_value: 8080 }      filter_chains:        - filters:            - name: envoy.filters.network.http_connection_manager              typed_config:                \"@type\": type.googleapis.com\/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager                codec_type: auto                stat_prefix: ingress_http                route_config:                  name: local_route                  virtual_hosts:                    - name: local_service                      domains: [\"*\"]                      routes:                        - match: { prefix: \"\/\" }                          route:                            cluster: echo_service                            timeout: 0s                            max_stream_duration:                              grpc_timeout_header_max: 0s                      cors:                        allow_origin_string_match:                          - prefix: \"*\"                        allow_methods: GET, PUT, DELETE, POST                        allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout                        max_age: \"1728000\"                        expose_headers: custom-header-1,grpc-status,grpc-message                http_filters:                  - name: envoy.filters.http.grpc_web                    typed_config:                      \"@type\": type.googleapis.com\/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb                  - name: envoy.filters.http.cors                    typed_config:                      \"@type\": type.googleapis.com\/envoy.extensions.filters.http.cors.v3.Cors                  - name: envoy.filters.http.router                    typed_config:                      \"@type\": type.googleapis.com\/envoy.extensions.filters.http.router.v3.Router  clusters:    - name: echo_service      connect_timeout: 0.25s      type: logical_dns      http2_protocol_options: {}      lb_policy: round_robin      load_assignment:        cluster_name: cluster_0        endpoints:          - lb_endpoints:              - endpoint:                  address:                    socket_address:                      address: 172.17.0.1                      port_value: 6565<\/code><\/pre>\n<h4>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 API<\/h4>\n<p>\u041a\u0430\u043a \u044f \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u043b \u0432 \u043d\u0430\u0447\u0430\u043b\u0435, \u0434\u043b\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0438\u0437 GitGub Packages \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e <a href=\"https:\/\/docs.github.com\/en\/authentication\/keeping-your-account-and-data-secure\/managing-your-personal-access-tokens\"><u>\u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u043e\u043a\u0435\u043d<\/u><\/a> \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438, \u0441 \u043f\u0440\u0430\u0432\u0430\u043c\u0438 \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u0435 \u043f\u0430\u043a\u0435\u0442\u043e\u0432.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f69\/97e\/f8a\/f6997ef8af390d9aaf4d5ed88209a8ec.png\" width=\"932\" height=\"92\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f69\/97e\/f8a\/f6997ef8af390d9aaf4d5ed88209a8ec.png\"\/><\/figure>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a GitHub Apache maven registry \u043d\u0430 \u0431\u044d\u043a\u0435\u043d\u0434\u0435 \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u0430\u043a\u0435\u0442:<\/p>\n<pre><code class=\"java\">repositories {    mavenCentral()    maven {        url = uri(\"https:\/\/maven.pkg.github.com\/arvgord\/bank-demo-api\")        credentials {            username = project.findProperty(\"gpr.user\") as String? ?: (\"GITHUB_ACTOR\")            password = project.findProperty(\"gpr.key\") as String? ?: (\"GITHUB_TOKEN\")        }    } }<\/code><\/pre>\n<p>\u0412 URL <a href=\"https:\/\/maven.pkg.github.com\/OWNER\/REPOSITORY\">https:\/\/maven.pkg.github.com\/OWNER\/REPOSITORY<\/a> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c OWNER \u043d\u0430 \u0438\u043c\u044f \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 \u043d\u0430 GitHub \u0438 REPOSITORY \u043d\u0430 \u0438\u043c\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u043e\u0442\u043a\u0443\u0434\u0430 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0435 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u043f\u0430\u043a\u0435\u0442. \u0412 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u0442\u043e\u043a\u0435\u043d \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u0435 GITHUB_TOKEN.<\/p>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u044b\u0437\u043e\u0432 gRPC API \u043d\u0430 \u0431\u044d\u043a\u0435\u043d\u0434\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0430\u043a\u0435\u0442\u0430:<\/p>\n<pre><code class=\"kotlin\">package com.arvgord.bankdemoserver.controller.grpc.cartesianissue.v1  import com.arvgord.api.grpc.bankdemo.v1.BankDemoGrpcKt import com.arvgord.api.grpc.bankdemo.v1.BankDemoOuterClass.GetClientListRequest import com.arvgord.api.grpc.bankdemo.v1.BankDemoOuterClass.GetClientListResponse import io.grpc.Status import io.grpc.StatusException import org.lognet.springboot.grpc.GRpcService import com.arvgord.bankdemoserver.controller.grpc.cartesianissue.v1.adapter.BankDemoAdapter  @GRpcService class BankDemoCartesianIssueController(    private val adapter: BankDemoAdapter ) : BankDemoGrpcKt.BankDemoCoroutineImplBase() {       override suspend fun getClientList(request: GetClientListRequest): GetClientListResponse =        try {            adapter.getClientList(request)        } catch (e: Exception) {            throw StatusException(Status.INTERNAL.withDescription(e.message))        } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a npm GitHub registry \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e:<\/p>\n<ol>\n<li>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 npm login &#8212;registry=https:\/\/npm.pkg.github.com.<\/p>\n<\/li>\n<li>\n<p>\u0412\u0432\u0435\u0441\u0442\u0438 \u0438\u043c\u044f \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 \u043d\u0430 GitHub \u0438 GITHUB_TOKEN \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u0435 \u043f\u0430\u043a\u0435\u0442\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c npm i \u0432 \u0432\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435.<\/p>\n<\/li>\n<\/ol>\n<p>\u0422\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432\u044b\u0437\u043e\u0432 gRPC API \u043d\u0430 React-\u043a\u043b\u0438\u0435\u043d\u0442\u0435:<\/p>\n<pre><code class=\"typescript\">import {useEffect, useState} from 'react'; import {GetClientListRequest, GetClientListResponse} from \"@arvgord\/bank-demo-api\/bankdemo\/v1\/api\/business\/bank_demo_pb\"; import {PageRequest} from \"@arvgord\/bank-demo-api\/bankdemo\/v1\/messages\/page_request_pb\"; import {Int32Value} from \"google-protobuf\/google\/protobuf\/wrappers_pb\"; import {ExtractingStrategy} from \"@arvgord\/bank-demo-api\/bankdemo\/v1\/messages\/extracting_strategy_pb\"; import {BankDemoPromiseClient} from \"@arvgord\/bank-demo-api\/bankdemo\/v1\/api\/business\/bank_demo_grpc_web_pb\";  export function useGetList(page: number, size: number, strategy: ExtractingStrategy) {    const [response, setResponse] = useState(new GetClientListResponse().toObject())    const [error, setError] = useState()     useEffect(() => {        if (!page &amp;&amp; !size &amp;&amp; !strategy) return        const service = new BankDemoPromiseClient('http:\/\/localhost:8080', null, null)        const request = new GetClientListRequest()        const pageRequest = new PageRequest()        pageRequest.setPage(new Int32Value().setValue(page))        pageRequest.setSize(new Int32Value().setValue(size))        request.setPageRequest(pageRequest)        request.setExtractingStrategy(strategy)        service.getClientList(request, {})            .then(result => result.toObject())            .then(setResponse)            .catch(setError)    }, [page, size, strategy]);     return {        response,        error    }; }<\/code><\/pre>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0433\u043e\u0442\u043e\u0432\u0430. \u0422\u0430\u043a \u043a\u0430\u043a \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043e\u0431\u0448\u0438\u0440\u043d\u044b\u043c, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a protolock protolint \u044f \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u044e \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f\u0445.<\/p>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0432\u044b \u043d\u0430\u0439\u0434\u0435\u0442\u0435 \u0432 <a href=\"https:\/\/github.com\/arvgord\/bank-demo-api\"><u>\u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043d\u0430 GitHub<\/u><\/a>, \u043a\u0430\u043a \u0438 \u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f <a href=\"https:\/\/github.com\/arvgord\/bank-demo\"><u>API<\/u><\/a> \u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0438 \u0431\u044d\u043a\u0435\u043d\u0434\u0443.<\/p>\n<h3>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h3>\n<p>gRPC \u2014 \u044d\u0442\u043e \u043c\u043e\u0449\u043d\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0438 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0445 API. \u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 .proto \u0444\u0430\u0439\u043b\u043e\u0432 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043e\u0434, \u0442\u0430\u043a \u0438 \u043a\u043e\u0434 \u0434\u043b\u044f \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432. \u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f gRPC API \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442\u0441\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c GitHub Actions \u0438 GitHub Packages, \u0447\u0442\u043e \u0438 \u0431\u044b\u043b\u043e \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0432 \u044d\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0435.<\/p>\n<\/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\/articles\/776962\/\"> https:\/\/habr.com\/ru\/articles\/776962\/<\/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-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u044d\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0435 \u044f \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e GitHub Actions \u043b\u0435\u0433\u043a\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044e gRPC API \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0432 GitHub Packages, \u0432 \u0440\u0435\u0435\u0441\u0442\u0440\u0430\u0445 Apache Maven \u0438 npm. \u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043e\u0441\u0432\u043e\u0438\u0442\u044c GitHub Packages \u0434\u043b\u044f \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0438 \u043d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c gRPC API \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430 Kotlin\/Java \u0438 gRPC-web \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u2014 \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n<figure class=\"full-width\"><\/figure>\n<h3>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0412\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u043a \u0434\u043e\u043a\u043b\u0430\u0434\u0443 <a href=\"https:\/\/habr.com\/ru\/companies\/rosbank\/articles\/743536\/\"><u>JPoint<\/u><\/a> \u0443 \u043c\u0435\u043d\u044f \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u0438\u0434\u0435\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0441\u0442\u0435\u043d\u0434, \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0438\u0439 \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442 \u0438 \u0431\u044d\u043a\u0435\u043d\u0434-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u042d\u0442\u043e\u0442 \u0441\u0442\u0435\u043d\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b \u0431\u044b \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0439 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f SQL-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441 \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u0435\u0439. \u0414\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0438 \u0431\u044d\u043a\u0435\u043d\u0434\u043e\u043c \u044f \u0440\u0435\u0448\u0438\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c gRPC. \u041c\u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439 \u0442\u0430\u043a\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u0438 \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f gRPC API \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e GitHub Actions \u0438 GitHub Packages. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u044d\u0442\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c \u0441 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u0425\u0430\u0431\u0440\u0430.<\/p>\n<h3>\u0412\u044b\u0431\u043e\u0440 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u0442\u0435\u043a\u0430 \u0438 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438<\/h3>\n<p>\u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b Kotlin, \u043e\u0434\u043d\u0430\u043a\u043e \u0432\u0441\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0434\u043b\u044f Java.<\/p>\n<p>\u042f \u0432\u044b\u0431\u0440\u0430\u043b Spring \u0438 Kotlin \u0434\u043b\u044f \u0431\u044d\u043a\u0435\u043d\u0434\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 React \u0441 TypeScript \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u0447\u0442\u043e \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u043b\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0443\u0436\u043d\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430. \u0412\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f gRPC \u2014 \u044d\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a Google, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b (RPC) \u043c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f Protocol Buffers \u043a\u0430\u043a \u044f\u0437\u044b\u043a \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430. gRPC \u0438\u043c\u0435\u0435\u0442 \u0440\u044f\u0434 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432:<\/p>\n<ul>\n<li>\n<p>\u0432\u044b\u0441\u043e\u043a\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 HTTP\/2;<\/p>\n<\/li>\n<li>\n<p>\u0441\u0442\u0440\u043e\u0433\u0430\u044f \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u044f Protocol Buffers, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0434\u0438\u0437\u0430\u0439\u043d\u0430 API \u0438 \u0441\u043d\u0438\u0436\u0430\u0435\u0442 \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043e\u043a \u043f\u0440\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432;<\/p>\n<\/li>\n<li>\n<p>.proto \u0444\u0430\u0439\u043b\u044b \u0441 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 API \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432 \u043a\u043e\u0434 \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u044f\u0437\u044b\u043a\u043e\u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0439 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b <a href=\"https:\/\/github.com\/grpc\/grpc-web\"><u>gRPC-web<\/u><\/a>, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 gRPC. gRPC-web \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u043e\u0431\u044b\u0447\u043d\u044b\u043c\u0438 gRPC-\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438 \u0438\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. \u041f\u043e\u043a\u0430 \u0447\u0442\u043e gRPC-web \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0432\u0430 \u0440\u0435\u0436\u0438\u043c\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f: \u0443\u043d\u0430\u0440\u043d\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u0438 server-side \u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433.<\/p>\n<h3>\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f<\/h3>\n<p>\u041c\u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u044b\u043c \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 gRPC API \u043f\u0430\u043a\u0435\u0442\u044b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/github.com\/features\/actions\"><u>GitHub Actions<\/u><\/a> \u0438 <a href=\"https:\/\/github.com\/features\/packages\"><u>GitHub Packages<\/u><\/a>. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0442\u043d\u0443\u044e \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 API \u0438 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c\u0443 style guide \u043e\u0442 Google \u0434\u043b\u044f .proto \u0444\u0430\u0439\u043b\u043e\u0432, \u044f \u0432\u043d\u0435\u0434\u0440\u0438\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/github.com\/nilslice\/protolock\"><u>protolock<\/u><\/a> \u0438 <a href=\"https:\/\/github.com\/yoheimuta\/protolint\"><u>protolint<\/u><\/a>.<\/p>\n<h3>\u041e \u0432\u044b\u0431\u043e\u0440\u0435 GitHub Packages<\/h3>\n<p>\u041f\u0440\u0438\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f GitHub Packages \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e \u0441 GitHub Actions, \u043f\u043e \u043c\u043e\u0435\u043c\u0443 \u043c\u043d\u0435\u043d\u0438\u044e, \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c:<\/p>\n<ul>\n<li>\n<p>\u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438 \u0434\u0435\u043f\u043b\u043e\u044f \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0432 GitHub Packages \u0432 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 \u0441 Maven Central;<\/p>\n<\/li>\n<li>\n<p>\u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u0441\u0435\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\u043a\u043e\u0434, CI\/CD \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u044b, \u043f\u0430\u043a\u0435\u0442\u044b) \u043d\u0430 GitHub, \u0447\u0442\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p>\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 \u0442\u0430\u0440\u0438\u0444, \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0438\u0439 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432 \u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u0445 \u0434\u0435\u043f\u043b\u043e\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u0441\u0435 \u044d\u0442\u0438 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0434\u0435\u043b\u0430\u044e\u0442 GitHub Actions \u0438 Packages \u0445\u043e\u0440\u043e\u0448\u0438\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0434\u043b\u044f Pet-\u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432. \u0422\u0435\u043c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435 \u0435\u0441\u0442\u044c \u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a: \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 Maven Central, \u0434\u043b\u044f \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f GitHub-\u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0438 \u0442\u043e\u043a\u0435\u043d \u0441 \u043f\u0440\u0430\u0432\u0430\u043c\u0438 \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u0435 \u043f\u0430\u043a\u0435\u0442\u043e\u0432. \u041a\u0430\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0442\u043e\u043a\u0435\u043d, \u044f \u043e\u043f\u0438\u0448\u0443 \u043d\u0438\u0436\u0435.\u00a0<\/p>\n<h3>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h3>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c Gradle-\u043f\u0440\u043e\u0435\u043a\u0442 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Kotlin DSL \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c .proto \u0444\u0430\u0439\u043b\u044b.<\/p>\n<p>Proto-\u0444\u0430\u0439\u043b API \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<pre><code class=\"kotlin\">syntax = \"proto3\";  package com.arvgord.api.grpc.bankdemo.v1;  import \"bankdemo\/v1\/messages\/client_list_item.proto\"; import \"bankdemo\/v1\/messages\/extracting_strategy.proto\"; import \"bankdemo\/v1\/messages\/page_request.proto\"; import \"google\/protobuf\/wrappers.proto\";  \/\/ Get client list request message GetClientListRequest {  \/\/ Current page  PageRequest page_request = 1;  \/\/ Extracting strategy  ExtractingStrategy extracting_strategy = 2; }  \/\/ Get client list response message GetClientListResponse {  \/\/ Clients  repeated ClientListItem clients = 1;  \/\/ Total number of clients  google.protobuf.Int64Value total_clients = 2;  \/\/ Total number of pages  google.protobuf.Int32Value total_pages = 3; }  \/\/ Service BankDemo service BankDemo {  \/\/ Get client list  rpc GetClientList(GetClientListRequest) returns (GetClientListResponse); }<\/code><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 .proto \u0444\u0430\u0439\u043b\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f PageRequest:<\/p>\n<pre><code class=\"kotlin\">syntax = \"proto3\";  package com.arvgord.api.grpc.bankdemo.v1;  import \"google\/protobuf\/wrappers.proto\";  \/\/ Page message PageRequest {  \/\/ Number of clients on page  google.protobuf.Int32Value page = 1;  \/\/ Page size  google.protobuf.Int32Value size = 2; }<\/code><\/pre>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h4>\n<p>\u0414\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432 \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043a\u043e\u0440\u0435\u043d\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0444\u0430\u0439\u043b gradle.properties \u0441 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439:<\/p>\n<pre><code class=\"kotlin\">kotlinVersion=1.9.10 protobufPluginVersion=0.9.4 protobufKotlinVersion=3.24.4 grpcProtobufVersion=1.58.0 grpcKotlinVersion=1.4.0<\/code><\/pre>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u0444\u0430\u0439\u043b settings.gradle.kts, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0443\u043a\u0430\u0436\u0435\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<pre><code class=\"kotlin\">rootProject.name = \"bank-demo-api\"<\/code><\/pre>\n<p>\u0410 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043c\u0435\u043d\u0435\u0434\u0436\u043c\u0435\u043d\u0442 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432:<\/p>\n<pre><code class=\"kotlin\">pluginManagement {    val kotlinVersion: String by settings    val protobufPluginVersion: String by settings    plugins {        kotlin(\"jvm\") version kotlinVersion        id(\"com.google.protobuf\") version protobufPluginVersion    }    repositories {        gradlePluginPortal()    } }<\/code><\/pre>\n<p>\u0412\u0435\u0440\u0441\u0438\u0438 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u0432 settings.gradle.kts \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u0432 gradle.properties, \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 build.gradle.kts. \u0427\u0442\u043e \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0445 \u0432\u0440\u0443\u0447\u043d\u0443\u044e.<\/p>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u0444\u0430\u0439\u043b build.gradle.kts. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u043b\u0430\u0433\u0438\u043d\u044b:<\/p>\n<pre><code class=\"kotlin\">plugins {    kotlin(\"jvm\")    id(\"com.google.protobuf\")    id(\"maven-publish\") }<\/code><\/pre>\n<p>\u042d\u0442\u0438 \u043f\u043b\u0430\u0433\u0438\u043d\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0434\u043b\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, .proto \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0432 Apache Maven registry GitHub.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0433\u0440\u0443\u043f\u043f\u0443 \u0438 \u0432\u0435\u0440\u0441\u0438\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 API, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442\u0430:<\/p>\n<pre><code class=\"kotlin\">group = \"com.arvgord\" version = \"0.0.1\"<\/code><\/pre>\n<p>\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 name \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u0437\u044f\u0442\u043e \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 settings.gradle.kts. \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u0441\u043b\u0435 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a: <code>com.arvgord:bank-demo-api:0.0.1<\/code>.<\/p>\n<p>\u0423\u043a\u0430\u0436\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 gRPC \u0438 Protocol Buffers \u0434\u043b\u044f Kotlin:<\/p>\n<pre><code class=\"kotlin\">dependencies {    implementation(\"io.grpc:grpc-kotlin-stub:${property(\"grpcKotlinVersion\")}\")    implementation(\"io.grpc:grpc-protobuf:${property(\"grpcProtobufVersion\")}\")    implementation(\"com.google.protobuf:protobuf-kotlin:${property(\"protobufKotlinVersion\")}\") }<\/code><\/pre>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 protobuf \u043f\u043b\u0430\u0433\u0438\u043d\u0430<\/h4>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043f\u043b\u0430\u0433\u0438\u043d protobuf, \u0447\u0442\u043e\u0431\u044b \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 .proto \u0444\u0430\u0439\u043b\u043e\u0432:<\/p>\n<pre><code class=\"kotlin\">protobuf {    protoc {        artifact = \"com.google.protobuf:protoc:${property(\"protobufKotlinVersion\")}\"    }    plugins {        id(\"grpc\") {            artifact = \"io.grpc:protoc-gen-grpc-java:${property(\"grpcProtobufVersion\")}\"        }        id(\"grpckt\") {            artifact = \"io.grpc:protoc-gen-grpc-kotlin:${property(\"grpcKotlinVersion\")}:jdk8@jar\"        }        id(\"protoc-gen-js\") {            path = projectDir.path.plus(\"\/tools\/protoc-gen-js-3.21.2-linux-x86_64\")        }        id(\"protoc-gen-grpc-web\") {            path = projectDir.path.plus(\"\/tools\/protoc-gen-grpc-web-1.4.2-linux-x86_64\")        }    }    generateProtoTasks {        all().forEach {            it.plugins {                id(\"grpc\")                id(\"grpckt\")                id(\"protoc-gen-js\") {                    option(\"import_style=commonjs,binary\")                }                id(\"protoc-gen-grpc-web\") {                    option(\"import_style=commonjs+dts,mode=grpcweb\")                }            }            it.builtins {                id(\"kotlin\")            }        }    } }<\/code><\/pre>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0441\u0435\u043a\u0446\u0438\u044e plugins:\u00a0<\/p>\n<ul>\n<li>\n<p>\u041f\u043b\u0430\u0433\u0438\u043d\u044b grpc \u0438 grpckt \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 Java-\u043a\u043e\u0434\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0433\u043e \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438\/\u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0433\u043e \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0433\u043e gRPC \u043a\u043e\u0434\u0430 \u043d\u0430 Kotlin.\u00a0<\/p>\n<\/li>\n<li>\n<p>\u041f\u043b\u0430\u0433\u0438\u043d <a href=\"https:\/\/github.com\/protocolbuffers\/protobuf-javascript\"><u>protoc-gen-js<\/u><\/a> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 JavaScript \u043a\u043e\u0434\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 .proto \u0444\u0430\u0439\u043b\u043e\u0432 \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438\/\u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e <a href=\"https:\/\/github.com\/protocolbuffers\/protobuf-javascript\/releases\"><u>\u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c<\/u><\/a> \u043f\u043b\u0430\u0433\u0438\u043d \u0438 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0435\u0433\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043b\u0430\u0433\u0438\u043d <a href=\"https:\/\/github.com\/grpc\/grpc-web\"><u>protoc-gen-grpc-web<\/u><\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 gRPC-\u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0438\u0437 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u042d\u0442\u043e\u0442 \u043f\u043b\u0430\u0433\u0438\u043d \u0442\u0430\u043a\u0436\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e <a href=\"https:\/\/github.com\/grpc\/grpc-web\/releases\"><u>\u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c<\/u><\/a> \u0438 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0443\u0442\u044c \u043a \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044e.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0441\u0435\u043a\u0446\u0438\u0438 generateProtoTasks \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0437\u0430\u0434\u0430\u0447\u0438 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u0434\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 .proto \u0444\u0430\u0439\u043b\u043e\u0432. protoc-gen-grpc-web \u043f\u043b\u0430\u0433\u0438\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a JS, \u0442\u0430\u043a \u0438 TypeScript \u043a\u043e\u0434. \u0422\u0430\u043a \u043a\u0430\u043a \u043c\u043d\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u044b\u043b\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c TypeScript \u043a\u043e\u0434 \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 gRPC \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0432 options protoc-gen-js \u0438 protoc-gen-grpc-web, \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 <code>import_style=commonjs,binary \u0438 import_style=commonjs+dts,mode=grpcweb<\/code>. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 <a href=\"https:\/\/github.com\/grpc\/grpc-web#import-style\"><u>\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438<\/u><\/a>.<\/p>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 Maven-\u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0430<\/h4>\n<p>\u0424\u0430\u0439\u043b build.gradle.kts \u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438:<\/p>\n<pre><code class=\"kotlin\">publishing {    repositories {        maven {            name = \"GitHubPackages\"            url = uri(\"https:\/\/maven.pkg.github.com\/arvgord\/bank-demo-api\")            credentials {                username = System.getenv(\"GITHUB_ACTOR\")                password = System.getenv(\"GITHUB_TOKEN\")            }        }    }    publications {        create&lt;MavenPublication>(\"maven\") {            from(components[\"kotlin\"])        }    } }<\/code><\/pre>\n<p>\u0412 URL \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f (<a href=\"https:\/\/maven.pkg.github.com\/OWNER\/REPOSITORY\">https:\/\/maven.pkg.github.com\/OWNER\/REPOSITORY<\/a>), \u043a\u0443\u0434\u0430 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u043a\u0435\u0442, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c OWNER \u043d\u0430 \u0438\u043c\u044f \u0432\u0430\u0448\u0435\u0433\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 \u043d\u0430 GitHub \u0438 REPOSITORY \u043d\u0430 \u0438\u043c\u044f \u0432\u0430\u0448\u0435\u0433\u043e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 username \u0438 password \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u0440\u0435\u0434\u044b GITHUB_ACTOR \u0438 GITHUB_TOKEN. \u041e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0432 GitHub Actions.<\/p>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 npm-\u043f\u0430\u043a\u0435\u0442\u0430<\/h4>\n<p>\u0414\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 npm-\u043f\u0430\u043a\u0435\u0442\u0430 \u044f \u0440\u0435\u0448\u0438\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e npm_package \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0443\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b package.json \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438. \u0412 build.gradle.kts \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0443 \u0434\u043b\u044f \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 TypeScript \u0438 JS \u0444\u0430\u0439\u043b\u043e\u0432 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e npm_package:<\/p>\n<pre><code class=\"kotlin\">tasks.register&lt;Copy>(\"buildAndCopy\") {    from(        projectDir.path.plus(\"\/build\/generated\/source\/proto\/main\/protoc-gen-js\"),        projectDir.path.plus(\"\/build\/generated\/source\/proto\/main\/protoc-gen-grpc-web\")    )    into(projectDir.path.plus(\"\/npm_package\/\")) }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0444\u0430\u0439\u043b\u0430 package.json, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0435\u0433\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 npm-\u043f\u0430\u043a\u0435\u0442\u0430:<\/p>\n<pre><code class=\"json\">{  \"name\":<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\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-361434","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/361434","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=361434"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/361434\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=361434"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=361434"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=361434"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}