{"id":332323,"date":"2022-04-24T03:00:11","date_gmt":"2022-04-24T03:00:11","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=332323"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=332323","title":{"rendered":"<span>GraphQL &amp;lt;-&amp;gt; gRPC API Gateway \u043d\u0430 Java<\/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<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/1cb\/12d\/132\/1cb12d13203de88853e7ce297ac1dafa.png\" width=\"782\" height=\"499\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1cb\/12d\/132\/1cb12d13203de88853e7ce297ac1dafa.png\"\/><figcaption><\/figcaption><\/figure>\n<p>API Gateway \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c. \u041e\u043d \u043c\u043e\u0436\u0435\u0442 \u0440\u0435\u0448\u0430\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438:<\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u0432 \u0440\u0430\u0437\u043d\u044b\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u0430\u0445. \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043d\u0438\u043c.<\/p>\n<\/li>\n<li>\n<p>\u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433.<\/p>\n<\/li>\n<li>\n<p>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0410\u0433\u0440\u0435\u0433\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 (\u043e\u0434\u0438\u043d \u0437\u0430\u043f\u0440\u043e\u0441 \u043a API Gateway &#8212; \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0431\u044d\u043a\u0443).<\/p>\n<\/li>\n<li>\n<p>\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0418 \u043c\u043d\u043e\u0433\u043e\u0435 \u0434\u0440\u0443\u0433\u043e\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 API Gateway \u0432\u0441\u0435 \u044d\u0442\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u043b\u043e\u0436\u0430\u0442\u0441\u044f \u043d\u0430 \u0431\u044d\u043a\u0435\u043d\u0434. \u0418 \u0435\u0441\u043b\u0438 \u0434\u043b\u044f \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u043f\u0440\u0430\u0432\u0434\u0430\u043d\u043e, \u0442\u043e \u0432 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445 \u043b\u044e\u0431\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0431\u0449\u0435\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u043f\u043e\u0432\u043b\u0435\u0447\u0451\u0442 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0432\u0441\u0435\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432.<\/p>\n<p>\u0415\u0441\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0445 \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439, \u0432 \u0442.\u0447. \u0438 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u0435\u0439\u0441\u0430 (GraphQL &lt;-> gRPC), \u043d\u043e \u043d\u0438 \u043e\u0434\u043d\u043e \u0438\u0437 \u043d\u0438\u0445 \u043d\u0435 \u043f\u043e\u0434\u043e\u0448\u043b\u043e \u043d\u0430\u043c \u0432 \u043f\u043e\u043b\u043d\u043e\u0439 \u043c\u0435\u0440\u0435.<\/p>\n<h2>\u041f\u043e\u0447\u0435\u043c\u0443 GraphQL<\/h2>\n<p>\u041d\u0430 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 API Gateway \u043d\u0443\u0436\u0435\u043d \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441 \u0444\u0440\u043e\u043d\u0442\u0430. \u041a\u043e\u0433\u0434\u0430 \u043c\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u043b\u0438, \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0432\u0438\u0434\u043e\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0431\u044b\u043b REST. \u041e\u043d \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442 \u0434\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043d\u043e \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430\u0447\u0430\u043b\u0438 \u043f\u0440\u043e\u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0435\u0433\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438:<\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0443\u0436\u043d\u043e \u043f\u0430\u0440\u0443 \u043f\u043e\u043b\u0435\u0439, \u043c\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u043b\u0438 \u0432\u0435\u0441\u044c \u043e\u0431\u044a\u0435\u043a\u0442. \u0414\u0430, \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 PATCH \u0438 \u043f\u0430\u0440\u0441\u0438\u0442\u044c \u043d\u0430 \u0431\u044d\u043a\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044f, \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043e \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c null \u0438 \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u0435 \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043e, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0434\u043b\u044f REST.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043d\u0443\u0436\u043d\u044b \u0432\u0441\u0435 \u043f\u043e\u043b\u044f. \u041c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0432\u043c\u0435\u0441\u0442\u043e \u043e\u0434\u043d\u043e\u0433\u043e, \u043d\u043e \u0442\u043e\u0433\u0434\u0430 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u0435\u0439\u0441\u0430 \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434. \u0410 \u0435\u0441\u043b\u0438 \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0439 \u0438 \u0442\u043e\u0439 \u0436\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0440\u043e\u043b\u044f\u043c\u0438 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0437\u043d\u044b\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u044b \u043a \u043f\u043e\u043b\u044f\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435, \u043a \u0442\u043e\u043c\u0443 \u0436\u0435, \u043c\u043e\u0433\u0443\u0442 \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f REST, \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0442 \u043f\u0430\u043a\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0444\u0440\u043e\u043d\u0442 \u0434\u0435\u043b\u0430\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b.<\/p>\n<\/li>\n<\/ul>\n<p>GraphQL, <a href=\"https:\/\/habr.com\/ru\/post\/425041\/\" rel=\"noopener noreferrer nofollow\">\u0445\u043e\u0442\u044c \u0438 \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438<\/a>, \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0440\u0435\u0448\u0430\u0435\u0442 \u044d\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u043e\u043d\u0443\u0441\u0430 \u0432 GraphQL \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 REST \u0435\u0441\u0442\u044c <a href=\"https:\/\/graphql.org\/learn\/queries\/#directives\" rel=\"noopener noreferrer nofollow\">\u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u044b<\/a>. \u0418\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u0451\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0434\u043b\u044f \u043f\u043e\u043b\u0435\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0438\u043c\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0438 \u043f\u0440\u043e\u0447\u0435\u0435.<\/p>\n<h2>\u041f\u043e\u0447\u0435\u043c\u0443 gRPC<\/h2>\n<p>\u0421 API \u0434\u043b\u044f \u0444\u0440\u043e\u043d\u0442\u0430 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043d\u0430 \u0431\u044d\u043a. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u0442\u0435 \u0436\u0435, \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043f\u0430\u043a\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u043d\u0430 \u0431\u044d\u043a\u0435 \u0442\u0430\u043a\u0438\u0445 \u043a\u0435\u0439\u0441\u043e\u0432 \u043d\u0435\u0442 \u0438 \u043d\u0435 \u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0438\u0442\u0441\u044f). \u041c\u043e\u0436\u043d\u043e \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c API \u0431\u044d\u043a\u0430 \u043d\u0430 GraphQL, \u044d\u0442\u043e \u0431\u044b \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u043b\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 API Gateway. \u041d\u043e \u043d\u0435 \u0432\u0441\u0451 \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e. <\/p>\n<p>\u041c\u044b \u043f\u0438\u0448\u0435\u043c \u043d\u0430 Java, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <a href=\"https:\/\/quarkus.io\" rel=\"noopener noreferrer nofollow\">Quarkus<\/a>, \u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 GraphQL \u0442\u0430\u043c \u0435\u0441\u0442\u044c \u043d\u0435\u043f\u043b\u043e\u0445\u0438\u0435 \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043a\u0430\u043a \u0434\u043b\u044f <a href=\"https:\/\/quarkus.io\/guides\/smallrye-graphql\" rel=\"noopener noreferrer nofollow\">\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438<\/a>, \u0442\u0430\u043a \u0438 \u0434\u043b\u044f <a href=\"https:\/\/quarkus.io\/guides\/smallrye-graphql-client\" rel=\"noopener noreferrer nofollow\">\u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432<\/a>. \u0421 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043d\u0435\u0442, \u043d\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0430\u044f \u0434\u0430\u043b\u0435\u043a\u0430 \u043e\u0442 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0441\u0442\u0432\u0430.<\/p>\n<p><a href=\"https:\/\/quarkus.io\/guides\/smallrye-graphql-client#using-the-typesafe-client\" rel=\"noopener noreferrer nofollow\">Typesafe-\u043a\u043b\u0438\u0435\u043d\u0442<\/a> \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442 \u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u0435\u043d.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0440<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">\/\/\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 @GraphQLClientApi(configKey = \"star-wars-typesafe\") public interface StarWarsClientApi {      FilmConnection allFilms();  }  \/\/\u043f\u0440\u0438\u043c\u0435\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 public class StarWarsResource {     @Inject     StarWarsClientApi typesafeClient;      public FilmConnection getAllFilms() {         return typesafeClient.allFilms();     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u0442\u0430\u043a\u043e\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0435 \u0434\u0430\u0451\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u0435\u043b\u0430\u0442\u044c \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u043e\u043b\u044f \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<p><a href=\"https:\/\/quarkus.io\/guides\/smallrye-graphql-client#using-the-dynamic-client\" rel=\"noopener noreferrer nofollow\">Dynamic-\u043a\u043b\u0438\u0435\u043d\u0442<\/a> \u043e\u0447\u0435\u043d\u044c \u0433\u0438\u0431\u043a\u0438\u0439. \u041c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0439 \u0443\u0433\u043e\u0434\u043d\u043e \u043d\u0430\u0431\u043e\u0440 \u043f\u043e\u043b\u0435\u0439, \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/graphql.org\/learn\/queries\/#variables\" rel=\"noopener noreferrer nofollow\">\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435<\/a>, \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432 \u043e\u0442\u0432\u0435\u0442\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0440<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public class StarWarsResource {      @Inject     @GraphQLClient(\"star-wars-dynamic\")     DynamicGraphQLClient dynamicClient;          public FilmConnection getAllFilmsUsingDynamicClient() {         Document query = document(                 operation(                         field(\"allFilms\",                                 field(\"films\",                                         field(\"title\"),                                         field(\"planetConnection\",                                                 field(\"planets\",                                                         field(\"name\")                                                 )                                         )                                 )                         )                 )         );         Response response = dynamicClient.executeSync(query);         return response.getObject(FilmConnection.class, \"allFilms\");     }  }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041d\u043e \u044d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u0433\u0440\u043e\u043c\u043e\u0437\u0434\u043a\u043e. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435 \u043f\u0440\u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0443.<\/p>\n<p>\u0412 gRPC \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u044b. \u0410 \u0434\u043b\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0432 \u043e\u0442\u0432\u0435\u0442, \u0435\u0441\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0442\u0438\u043f &#8212; <a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/reference\/csharp\/class\/google\/protobuf\/well-known-types\/field-mask\" rel=\"noopener noreferrer nofollow\">FieldMask<\/a>.<\/p>\n<p>\u0412 gRPC \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432-\u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f protobuf. \u0415\u0433\u043e \u0436\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u043b\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438 \u0447\u0435\u0440\u0435\u0437 kafka. \u0422.\u043e. \u043d\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u043b\u043e\u0434\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442\u044b, \u0438 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0431\u044d\u043a\u0435 \u0447\u0442\u043e-\u0442\u043e \u043e\u0434\u043d\u043e.<\/p>\n<p>\u0427\u0430\u0441\u0442\u043e, \u043a\u043e\u0433\u0434\u0430 \u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u043e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430\u0445 gRPC, \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u044e\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0441\u043d\u0438\u0436\u0430\u044e\u0449\u0435\u0439 \u043d\u0430\u043a\u043b\u0430\u0434\u043d\u044b\u0435 \u0440\u0430\u0441\u0445\u043e\u0434\u044b. \u041c\u044b \u043a \u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u043a\u0430 \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u0438, \u043d\u043e \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c.<\/p>\n<p>\u0412 protobuf \u0435\u0441\u0442\u044c <a href=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/546182\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0441 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 null-\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439<\/a>, \u043d\u043e \u0435\u0451 \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043f\u043e-\u0441\u0432\u043e\u0435\u043c\u0443 (\u043e\u0431 \u044d\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u0434\u0430\u043b\u0435\u0435).<\/p>\n<h2>\u0413\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f<\/h2>\n<p>\u0420\u0430\u043d\u0435\u0435 \u044f \u043f\u0438\u0441\u0430\u043b, \u0447\u0442\u043e \u043d\u0430 \u0431\u044d\u043a\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c Java \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043d\u0430\u0439\u0442\u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u0433\u043e\u0442\u043e\u0432\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u043d\u0451\u043c. \u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435, \u0447\u0442\u043e \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0439\u0442\u0438, \u044d\u0442\u043e \u043f\u0440\u043e\u0435\u043a\u0442 <a href=\"https:\/\/rejoiner.io\/\" rel=\"noopener noreferrer nofollow\">Rejoiner<\/a>. \u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u043a\u043e\u0440\u043e\u0431\u043e\u0447\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430 \u043d\u0443\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u0447\u0442\u043e \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e, \u0442.\u043a. \u043f\u0440\u0438 \u0435\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438\/\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442. \u0415\u0449\u0451 \u043e\u0434\u0438\u043d \u043c\u0438\u043d\u0443\u0441 &#8212; \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0435 \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0435\u0442\u0441\u044f. \u041e\u0434\u043d\u0430\u043a\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u0432 \u0435\u0433\u043e \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u0445 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0447\u0435\u0440\u043f\u043d\u0443\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e API Gateway.<\/p>\n<p>\u0415\u0449\u0451 \u043e\u0434\u0438\u043d \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 &#8212; <a href=\"https:\/\/www.graphql-mesh.com\/\" rel=\"noopener noreferrer nofollow\">GraphQL Mesh<\/a> &#8212; \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 TypeScript \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 \u0438\u0437 GraphQL \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 gRPC, \u043d\u043e \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f. \u041d\u043e \u043e\u043d \u043d\u0435 \u0434\u0430\u0451\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u0442\u0438\u043f\u043e\u0432 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u0432\u043e\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u0412\u0441\u0451 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0430\u043c\u0438\u043c, \u043d\u043e \u043f\u0438\u0448\u0435\u043c \u043c\u044b \u043d\u0430 Java.<\/p>\n<p>\u0415\u0441\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0430 Go, \u043d\u043e \u043e\u043d\u0438 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e API Gateway \u0438\u0437 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430, \u0447\u0442\u043e \u043d\u0430\u0441 \u043d\u0435 \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442. \u0412 \u0438\u0442\u043e\u0433\u0435 \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 API Gateway \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0441\u0442\u044d\u043a\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439.<\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h2>\n<p>\u0421\u043f\u0438\u0441\u043e\u043a \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043a \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443:<\/p>\n<ul>\n<li>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 Java\/Quarkus.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043a\u043e\u0434\u043e\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 DTO \u0438 \u0441\u0442\u0430\u0431\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u043e\u0441\u043b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f API \u043a\u0430\u043a\u043e\u0433\u043e-\u043b\u0438\u0431\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c &#171;\u0433\u043e\u0440\u044f\u0447\u0435\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f&#187; \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430. \u041f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430 \u0431\u044d\u043a\u0435 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u0434 API Gateway.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 batch-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<h3>\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/h3>\n<details class=\"spoiler\">\n<summary>build.gradle<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">ext {         quarkusVersion = \"2.7.4.Final\"         graphqlVersion = \"17.0\"         lombokVersion = \"1.18.22\" }  dependencies {     implementation(             platform(\"io.quarkus:quarkus-bom:$quarkusVersion\"),             \"io.quarkus:quarkus-config-yaml\",             \"io.quarkus:quarkus-grpc-common\",             \"io.quarkus:quarkus-grpc-stubs\",             \"com.graphql-java:graphql-java-extended-scalars:$graphqlVersion\",             \"com.graphql-java:graphql-java-extended-validation:$graphqlVersion\",             \"io.vertx:vertx-web-graphql\",             \"com.google.protobuf:protobuf-java-util\",             \"com.fasterxml.jackson.core:jackson-databind\",     )     compileOnly(\"org.projectlombok:lombok:$lombokVersion\")     annotationProcessor(\"org.projectlombok:lombok:$lombokVersion\") }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><code>quarkus-...<\/code> &#8212; \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 YAML-\u043a\u043e\u043d\u0444\u0438\u0433\u043e\u043c \u0438 gRPC.<br \/><code>graphql-java-extended-scalars<\/code> &#8212; \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043a\u0430\u043b\u044f\u0440\u044b GraphQL. \u0418\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0435 \u0442\u0430\u043a \u043c\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u043e\u0432, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0435 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c.<br \/><code>graphql-java-extended-validation<\/code> &#8212; \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u044b \u0434\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<br \/><code>protobuf-java-util<\/code> &#8212; \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432-\u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043e\u0442 gRPC-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON.<br \/><code>jackson-databind<\/code> &#8212; \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0433\u043e \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON.<br \/><code>lombok<\/code> &#8212; \u043f\u0435\u0440\u0447\u0438\u043a.<br \/><code>vertx-web-graphql<\/code> &#8212; \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 GraphQL \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e&#8230; Vertx.<\/p>\n<p>\u0425\u043e\u0442\u044f Quarkus \u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c \u0434\u043b\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u043e \u043e\u043d, \u043a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0431\u043e\u043b\u044c\u0448\u0435 \u0437\u0430\u0442\u043e\u0447\u0435\u043d \u043d\u0430 \u043f\u043e\u0434\u0445\u043e\u0434 code-first, \u0430 \u043c\u044b \u0441\u0442\u0440\u043e\u0433\u043e \u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u0434\u0445\u043e\u0434\u0430 contract-first. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435 \u043f\u0440\u0438 \u043f\u043e\u0434\u0445\u043e\u0434\u0435 code-first \u043d\u0430\u043c \u0431\u044b \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442 Quarkus \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0431\u0443\u0434\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e DI, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a gRPC-\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c. \u0410 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 Vertx.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0443 Quarkus \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f Vertx, \u0447\u0442\u043e \u0431\u044b\u0432\u0430\u0435\u0442 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0445 \u0432\u0435\u0449\u0435\u0439. \u0421\u0435\u0440\u0432\u0435\u0440\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c Quarkus \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 Vertx, \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 REST\/GraphQL \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 HTTP-\u043a\u043b\u0438\u0435\u043d\u0442 \u0438\u0437 Vertx, \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0411\u0414 \u0438\u0434\u0451\u0442 \u0447\u0435\u0440\u0435\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Vertx. \u041e\u0434\u043d\u0430\u043a\u043e \u043d\u0435 \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0435\u0441\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0432 Vertx, \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 Quarkus. \u0421\u0435\u0440\u0432\u0435\u0440\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0434\u043b\u044f GraphQL \u0438 \u043e\u0431\u0451\u0440\u0442\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 gRPC \u0432 Quarkus \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Vertx.<\/p>\n<\/div>\n<\/details>\n<h3>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<\/h3>\n<p>\u041a\u0430\u043a \u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c GraphQL, \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 <a href=\"https:\/\/vertx.io\/docs\/vertx-web-graphql\/java\/\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 Vertx<\/a> \u0438 <a href=\"https:\/\/www.graphql-java.com\/documentation\/getting-started\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 graphql-java<\/a>. \u0412 \u0438\u0442\u043e\u0433\u0435 \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u0442\u0430\u043a\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f:<\/p>\n<details class=\"spoiler\">\n<summary>\u0424\u0430\u0431\u0440\u0438\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f GraphQL<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">package ru.craftysoft.platform.gateway.configuration;  import graphql.GraphQL; import graphql.language.FieldDefinition; import graphql.language.ObjectTypeDefinition; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import graphql.schema.idl.SchemaGenerator; import graphql.schema.idl.SchemaParser; import graphql.schema.idl.TypeDefinitionRegistry; import graphql.schema.idl.TypeRuntimeWiring; import graphql.validation.constraints.standard.SizeConstraint; import graphql.validation.rules.OnValidationErrorStrategy; import graphql.validation.rules.ValidationRules; import graphql.validation.schemawiring.ValidationSchemaWiring; import io.vertx.core.Future; import io.vertx.ext.web.handler.graphql.schema.VertxDataFetcher; import lombok.NoArgsConstructor;  import java.util.Collection; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors;  import static graphql.scalars.ExtendedScalars.*; import static graphql.schema.idl.RuntimeWiring.newRuntimeWiring; import static lombok.AccessLevel.PRIVATE;  @NoArgsConstructor(access = PRIVATE) public class GraphQlFactory {      private static final LoggingInstrumentation loggingInstrumentation = new LoggingInstrumentation();      public static &lt;T> GraphQL graphQl(Function&lt;DataFetchingEnvironment, Future&lt;T>> dataFetcher, String graphql) {         var typeRegistry = new SchemaParser().parse(graphql);         var validationRules = ValidationRules.newValidationRules()                 .onValidationErrorStrategy(OnValidationErrorStrategy.RETURN_NULL)                 .addRule(new SizeConstraint())                 .build();         var queries = resolveMethods(typeRegistry, \"Query\");         var mutations = resolveMethods(typeRegistry, \"Mutation\");         var runtimeWiring = newRuntimeWiring()                 .directiveWiring(new ValidationSchemaWiring(validationRules))                 .scalar(GraphQLLong)                 .scalar(DateTime)                 .scalar(Date)                 .type(\"Query\", builder -> resolveBuilder(queries, dataFetcher, builder))                 .type(\"Mutation\", builder -> resolveBuilder(mutations, dataFetcher, builder))                 .build();         var graphQLSchema = new SchemaGenerator().makeExecutableSchema(typeRegistry, runtimeWiring);         return GraphQL.newGraphQL(graphQLSchema)                 .instrumentation(loggingInstrumentation)                 .build();     }      private static List&lt;String> resolveMethods(TypeDefinitionRegistry typeRegistry, String type) {         return typeRegistry.getType(type)                 .map(ObjectTypeDefinition.class::cast)                 .map(ObjectTypeDefinition::getChildren)                 .stream()                 .flatMap(Collection::stream)                 .map(FieldDefinition.class::cast)                 .map(FieldDefinition::getName)                 .toList();     }      private static &lt;T> TypeRuntimeWiring.Builder resolveBuilder(List&lt;String> methods,                                                                 Function&lt;DataFetchingEnvironment, Future&lt;T>> dataFetcher,                                                                 TypeRuntimeWiring.Builder builder) {         var dataFetcherMap = methods.stream()                 .collect(Collectors.toMap(name -> name, name -> (DataFetcher) VertxDataFetcher.create(dataFetcher)));         return builder.dataFetchers(dataFetcherMap);     }  }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f:<\/p>\n<ul>\n<li>\n<p>\u043f\u0430\u0440\u0441\u0438\u0442\u0441\u044f \u0441\u0445\u0435\u043c\u0430 graphql<\/p>\n<\/li>\n<li>\n<p>\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0439 (\u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e <code>SizeConstraint<\/code> \u0438\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <a href=\"https:\/\/github.com\/graphql-java\/graphql-java-extended-validation\" rel=\"noopener noreferrer nofollow\">graphql-java-extended-validation<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u044b <a href=\"https:\/\/github.com\/graphql-java\/graphql-java-extended-validation#size\" rel=\"noopener noreferrer nofollow\">@Size<\/a>)<\/p>\n<\/li>\n<li>\n<p>\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0434\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432 <code>Query<\/code> \u0438 <code>Mutation<\/code> (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u043e\u0434\u0438\u043d \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432)<\/p>\n<\/li>\n<li>\n<p>\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u043a\u0430\u043b\u044f\u0440\u044b <code>GraphQLLong<\/code>, <code>DateTime<\/code>, <code>Date<\/code> \u0434\u043b\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0442\u0438\u043f\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f <a href=\"https:\/\/www.graphql-java.com\/documentation\/instrumentation\/\" rel=\"noopener noreferrer nofollow\">Instrumentation<\/a> \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ul>\n<details class=\"spoiler\">\n<summary>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0431\u0438\u043d\u0430 GraphQL<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">package ru.craftysoft.platform.gateway.configuration;  import graphql.GraphQL; import lombok.SneakyThrows; import ru.craftysoft.platform.gateway.resolver.MainResolver;  import javax.enterprise.context.ApplicationScoped; import java.nio.charset.StandardCharsets; import java.util.Objects;  @ApplicationScoped public class GraphQlConfiguration {      @ApplicationScoped     public GraphQL graphQl(MainResolver mainResolver) {         var contract = parse();         return GraphQlFactory.graphQl(mainResolver::resolve, contract);     }      @SneakyThrows     private String parse() {         var graphqlAsBytes = Objects.requireNonNull(GraphQlConfiguration.class.getResourceAsStream(\"\/gateway.graphqls\"))                 .readAllBytes();         return new String(graphqlAsBytes, StandardCharsets.UTF_8);     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">package ru.craftysoft.platform.gateway.handler;  import graphql.GraphQL; import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.handler.graphql.GraphQLHandler; import io.vertx.ext.web.handler.graphql.GraphQLHandlerOptions; import lombok.RequiredArgsConstructor;  import javax.enterprise.context.ApplicationScoped;  @ApplicationScoped @RequiredArgsConstructor public class MainHandler {      private final GraphQL graphQl;     private final GraphQLHandlerOptions graphQlHandlerOptions = new GraphQLHandlerOptions().setRequestBatchingEnabled(true);      public void graphqlHandle(RoutingContext routingContext) {         GraphQLHandler.create(graphQl, graphQlHandlerOptions).handle(routingContext);     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0443\u0442 \u0441\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 <code>.setRequestBatchingEnabled(true)<\/code>. \u0417\u0430 \u0441\u0447\u0451\u0442 \u044d\u0442\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u043c\u044b \u0434\u0435\u043b\u0430\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 <a href=\"https:\/\/www.graphql-java.com\/documentation\/batching\/\" rel=\"noopener noreferrer nofollow\">batch-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/a> \u043a API Gateway.<\/p>\n<details class=\"spoiler\">\n<summary>\u0412\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">package ru.craftysoft.platform.gateway.configuration;  import io.vertx.core.Vertx; import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.BodyHandler; import ru.craftysoft.platform.gateway.handler.MainHandler;  import javax.enterprise.context.ApplicationScoped;  @ApplicationScoped public class RouterConfiguration {      public static final String GRAPHQL_ROUTE_PATH = \"\/graphql\";      @ApplicationScoped     public Router router(Vertx vertx, MainHandler mainHandler) {         var router = Router.router(vertx);         var bodyHandler = BodyHandler.create();         router.post().handler(bodyHandler);         router.post(GRAPHQL_ROUTE_PATH)                 .handler(mainHandler::graphqlHandle);         return router;     }  }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h3>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0440\u0430\u0431\u043e\u0442\u044b<\/h3>\n<h4>\u0420\u043e\u0443\u0442\u0438\u043d\u0433<\/h4>\n<p>\u0423 \u043c\u0435\u043d\u044f \u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u0437\u0430\u0448\u0438\u0442 \u043f\u0440\u044f\u043c\u043e \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u042d\u0442\u043e \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0430, \u043d\u043e \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043b\u0443\u0447\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 (\u0411\u0414, \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u043a\u044d\u0448), \u0442.\u043a. \u043f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0431\u0443\u0434\u0435\u0442 \u043e\u0447\u0435\u043d\u044c \u0433\u0440\u043e\u043c\u043e\u0437\u0434\u043a\u0438\u043c \u0438 \u043d\u0435\u0447\u0438\u0442\u0430\u0435\u043c\u044b\u043c.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430 \u0432 application.yaml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"yaml\">graphql:   services-by-methods:     filter: grpc-service     getById: grpc-service     update: grpc-service     empty: grpc-service grpc:   services:     grpc-service:       service-name: \"ru.craftysoft.platform.grpcservice.proto.GrpcService\"       host: 0.0.0.0       port: 9000       reflection-client-deadline: 1000       dynamic-client-deadline: 2000<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041c\u0430\u043f\u043f\u0438\u043d\u0433 \u043c\u0435\u0442\u043e\u0434\u043e\u0432<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">package ru.craftysoft.platform.gateway.configuration.property;  import io.smallrye.config.ConfigMapping;  import java.util.Map;  @ConfigMapping(prefix = \"graphql\") public interface GraphQlServersByMethodsMap {      Map&lt;String, String> serversByMethods();  }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041c\u0430\u043f\u043f\u0438\u043d\u0433 gRPC-\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">package ru.craftysoft.platform.gateway.configuration.property;  import io.smallrye.config.ConfigMapping;  import java.util.Map;  @ConfigMapping(prefix = \"grpc\") public interface GrpcClientConfigurationMap {     Map&lt;String, ServerConfiguration> services();      interface ServerConfiguration {         String serviceName();          String host();          int port();          long reflectionClientDeadline();          long dynamicClientDeadline();     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e Quarkus-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432 <a href=\"https:\/\/quarkus.io\/guides\/config-mappings\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a>. \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u044f \u043d\u0435 \u0434\u0435\u043b\u0430\u043b \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 GraphQL \u0432 \u043c\u0435\u0442\u043e\u0434\u044b gRPC \u0438 \u0441\u0447\u0438\u0442\u0430\u044e, \u0447\u0442\u043e \u0443 \u043e\u043d\u0438 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e. \u0422.\u043e. \u043c\u043d\u0435 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u0441\u043c\u0430\u043f\u043f\u0438\u0442\u044c \u043c\u0435\u0442\u043e\u0434 GraphQL \u0432 \u0441\u0435\u0440\u0432\u0438\u0441 gRPC.<\/p>\n<h4>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0430 gRPC<\/h4>\n<p>Proto &#8212; \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u043e \u0441\u0442\u0440\u043e\u0433\u043e\u0439 \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u0435\u0439. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u043c\u0435\u0442\u044c \u0443 \u0441\u0435\u0431\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e\u0442\u0441\u044f DTO \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432\/\u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0438 \u0441\u0442\u0430\u0431\u044b. \u0421 \u0443\u0447\u0451\u0442\u043e\u043c \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u044b gRPC-\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043b\u0435\u0436\u0430\u0442 \u0432 \u043d\u0438\u0445 \u0441\u0430\u043c\u0438\u0445, \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u0445 \u043d\u0443\u0436\u043d\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u0442\u0442\u0443\u0434\u0430. \u041f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u043d\u0435 \u0442\u0430\u043a \u043c\u043d\u043e\u0433\u043e, \u044f \u043d\u0430\u0448\u0451\u043b <a href=\"https:\/\/github.com\/grpc-ecosystem\/polyglot\/blob\/master\/src\/main\/java\/me\/dinowernli\/grpc\/polyglot\/grpc\/ServerReflectionClient.java\" rel=\"noopener noreferrer nofollow\">\u0442\u0430\u043a\u043e\u0439<\/a>, \u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043e\u043d \u0441\u0442\u0440\u0430\u0448\u043d\u043e\u0432\u0430\u0442\u043e. \u0412 \u043d\u0451\u043c \u043d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 <code>lookupService<\/code>. \u041f\u043e\u0441\u043b\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<details class=\"spoiler\">\n<summary>gRPC-\u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">package ru.craftysoft.platform.gateway.service.client.grpc;  import io.grpc.CallOptions; import io.grpc.Channel; import io.grpc.Deadline; import io.grpc.reflection.v1alpha.ServerReflectionRequest; import io.grpc.reflection.v1alpha.ServerReflectionResponse; import io.smallrye.mutiny.Uni; import lombok.RequiredArgsConstructor;  import java.util.concurrent.TimeUnit;  import static io.grpc.reflection.v1alpha.ServerReflectionGrpc.getServerReflectionInfoMethod;  @RequiredArgsConstructor public class ReflectionGrpcClient {     private final Channel channel;     private final long deadline;      public Uni&lt;ServerReflectionResponse> serverReflectionInfo(ServerReflectionRequest request) {         var call = channel                 .newCall(                         getServerReflectionInfoMethod(),                         CallOptions.DEFAULT.withDeadline(Deadline.after(deadline, TimeUnit.MILLISECONDS))                 );         return io.quarkus.grpc.runtime.ClientCalls.oneToOne(                 request,                 (message, streamObserver) -> io.grpc.stub.ClientCalls.asyncUnaryCall(call, message, streamObserver)         );     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0424\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">package ru.craftysoft.platform.gateway.builder.reflection;  import io.grpc.reflection.v1alpha.ServerReflectionRequest;  import javax.enterprise.context.ApplicationScoped;  @ApplicationScoped public class ServerReflectionRequestBuilder {      public ServerReflectionRequest build(String serviceName) {         return ServerReflectionRequest.newBuilder()                 .setFileContainingSymbol(serviceName)                 .build();     }  }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><code>serviceName<\/code> &#8212; \u043f\u043e\u043b\u043d\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u044f \u043f\u043e\u043b\u0443\u0447\u0430\u044e \u0438\u0437 \u043a\u043e\u043d\u0444\u0438\u0433\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <strong>ru.craftysoft.platform.grpcservice.proto.GrpcService<\/strong>.<br \/> \u0412 \u043a\u043e\u0434\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0441\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043c\u0435\u0442\u043e\u0434 <code>io.quarkus.grpc.runtime.ClientCalls.oneToOne()<\/code>, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0439 \u043e\u0442\u0432\u0435\u0442, \u043e\u0431\u0451\u0440\u043d\u0443\u0442\u044b\u0439 \u0432 <code>io.smallrye.mutiny.Uni<\/code>. \u0412 Quarkus \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <a href=\"https:\/\/smallrye.io\/smallrye-mutiny\/\" rel=\"noopener noreferrer nofollow\">smallrye-mutiny<\/a>, \u0430 Uni &#8212; \u044d\u0442\u043e \u043e\u0434\u043d\u043e \u0438\u0437 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430, \u0430\u043d\u0430\u043b\u043e\u0433 Mono \u0438\u0437 <a href=\"https:\/\/projectreactor.io\/\" rel=\"noopener noreferrer nofollow\">project-reactor<\/a>.<\/p>\n<p>\u0418\u0437 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0430\u043c \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u044c \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u0445 \u0438 \u043c\u0435\u0442\u043e\u0434\u0430\u0445. \u0412 \u043e\u0442\u0432\u0435\u0442\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 <code>com.google.protobuf.DescriptorProtos.FileDescriptorProto<\/code> \u0432 \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u043c \u0432\u0438\u0434\u0435. \u0418\u0437 \u043d\u0435\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0435 \u0441 \u0443\u0447\u0451\u0442\u043e\u043c \u0432\u0441\u0435\u0445 \u0435\u0433\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u0442.\u043a. \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438\u0437 \u0440\u0430\u0437\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432, \u0432\u043a\u043b\u044e\u0447\u0430\u044f proto-\u0444\u0430\u0439\u043b\u044b \u0438\u0437 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a.<\/p>\n<h4>\u0424\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043a gRPC-\u0441\u0435\u0440\u0432\u0438\u0441\u0443<\/h4>\n<p>\u041c\u0430\u043f\u043f\u0438\u043d\u0433 JSON-\u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a gRPC-\u0441\u0435\u0440\u0432\u0438\u0441\u0443 \u044f \u043f\u043e\u0434\u0441\u043c\u043e\u0442\u0440\u0435\u043b \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 Rejoiner, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043b \u0440\u0430\u043d\u0435\u0435, \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0442\u0443\u0434\u0430 \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u043a\u043b\u0430\u0441\u0441\u043e\u0432-\u043e\u0431\u0451\u0440\u0442\u043e\u043a \u0434\u043b\u044f nullable-\u0442\u0438\u043f\u043e\u0432.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 protobuf \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c null-\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u0412 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b-\u043e\u0431\u0451\u0440\u0442\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0435\u0441\u0442\u044c \u0432 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a StringValue, BooleanValue, \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044f \u0438\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043a\u0430\u043a null. \u041d\u043e \u0435\u0441\u043b\u0438 \u0434\u043b\u044f \u0441\u0442\u0440\u043e\u043a (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435) \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c, \u0442.\u043a. \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0442\u0430\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0443\u0441\u0442\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430, \u0442\u043e 0 \u0434\u043b\u044f \u0447\u0438\u0441\u043b\u043e\u0432\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u043d\u0430\u0441 \u043d\u0435\u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c. \u042f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 proto-\u0444\u0430\u0439\u043b \u0441 \u043e\u0431\u0451\u0440\u0442\u043a\u0430\u043c\u0438 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043e\u0432, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f google.protobuf.NullValue \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 null.<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430:<\/p>\n<ul>\n<li>\n<p>\u041d\u0435\u043b\u044c\u0437\u044f \u0441\u043c\u0430\u043f\u043f\u0438\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0449\u0438\u0439 \u0431\u043e\u043b\u0435\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0442 \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 \u0434\u043b\u044f <a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/proto3#oneof\" rel=\"noopener noreferrer nofollow\">oneof<\/a>. \u0418\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 nullable-\u0442\u0438\u043f\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 gRPC \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u043d\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0437\u0430 null.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0442 \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 \u0434\u043b\u044f <a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/proto3#maps\" rel=\"noopener noreferrer nofollow\">map&lt;key, value><\/a>, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432 GraphQL \u043d\u0435\u0442 \u0430\u043d\u0430\u043b\u043e\u0433\u0430. \u041d\u0435 \u0442\u043e, \u0447\u0442\u043e\u0431\u044b \u044f \u0447\u0430\u0441\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u044d\u0442\u0438\u043c \u0442\u0438\u043f\u043e\u043c \u0432 gRPC, \u043d\u043e \u0432 \u043f\u0430\u0440\u0435 REST-\u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043e\u043d \u0435\u0441\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p>\u041c\u0430\u043f\u043f\u0438\u043d\u0433 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u0432 FieldMask \u0432\u043e\u0437\u043c\u043e\u0436\u0435\u043d, \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 FieldMask \u043b\u0435\u0436\u0438\u0442 \u0432 \u043a\u043e\u0440\u043d\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0432 proto. \u0412 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e.<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u0440\u043e\u043c\u0435 \u0441\u0430\u043c\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440 \u043c\u0435\u0442\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u0442\u0438\u043f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441, \u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433), \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 \u0438 \u043c\u0430\u0440\u0448\u0430\u043b\u043b\u0435\u0440\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0430\/\u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<details class=\"spoiler\">\n<summary>\u0424\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0430 \u043c\u0435\u0442\u043e\u0434\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">package ru.craftysoft.platform.gateway.builder.dynamic;  import com.google.protobuf.Descriptors; import com.google.protobuf.DynamicMessage; import com.google.protobuf.ExtensionRegistryLite; import io.grpc.MethodDescriptor;  import javax.enterprise.context.ApplicationScoped; import java.io.IOException; import java.io.InputStream;  import static io.grpc.MethodDescriptor.MethodType.UNARY;  @ApplicationScoped public class DynamicMessageMethodDescriptorBuilder {      public MethodDescriptor&lt;DynamicMessage, DynamicMessage> build(String serviceName,                                                                   String methodName,                                                                   Descriptors.Descriptor inputType,                                                                   Descriptors.Descriptor outputType) {         var fullMethodName = MethodDescriptor.generateFullMethodName(serviceName, methodName);         return MethodDescriptor.&lt;DynamicMessage, DynamicMessage>newBuilder()                 .setType(UNARY)                 .setFullMethodName(fullMethodName)                 .setRequestMarshaller(new DynamicMessageMarshaller(inputType))                 .setResponseMarshaller(new DynamicMessageMarshaller(outputType))                 .build();     }      private static class DynamicMessageMarshaller implements MethodDescriptor.Marshaller&lt;DynamicMessage> {         private final Descriptors.Descriptor messageDescriptor;          public DynamicMessageMarshaller(Descriptors.Descriptor messageDescriptor) {             this.messageDescriptor = messageDescriptor;         }          @Override         @SneakyThrows         public DynamicMessage parse(InputStream inputStream) {             return DynamicMessage.newBuilder(messageDescriptor)                     .mergeFrom(inputStream, ExtensionRegistryLite.getEmptyRegistry())                     .build();         }          @Override         public InputStream stream(DynamicMessage abstractMessage) {             return abstractMessage.toByteString().newInput();         }     }  }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441 \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430.<\/p>\n<h4>\u041c\u0430\u043f\u043f\u0438\u043d\u0433 \u043e\u0442\u0432\u0435\u0442\u0430<\/h4>\n<p>\u0412 \u0441\u0430\u043c\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0434\u043b\u044f \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430 \u0432 JSON \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/reference\/java\/com\/google\/protobuf\/util\/JsonFormat.Printer.html#print-com.google.protobuf.MessageOrBuilder-\" rel=\"noopener noreferrer nofollow\">com.google.protobuf.util.JsonFormat.printer().print(MessageOrBuilder message)<\/a>, \u043d\u043e \u0442\u0430\u043c \u043d\u0435\u0442 \u0438 \u0431\u044b\u0442\u044c \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 nullable-\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u0434\u0430\u0442\u044b \u0438 \u0434\u0430\u0442\u044b-\u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0412 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u043c \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u0432 JSON \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442 \u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0439 \u043e\u0431\u0445\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430 \u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0435\u0433\u043e \u0432 Map&lt;String, Object>.<\/p>\n<h2>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/h2>\n<p>\u0413\u043e\u0442\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 <a href=\"https:\/\/github.com\/estet90\/platform-concept\/tree\/master\" rel=\"noopener noreferrer nofollow\">Github<\/a>. \u041e\u043d \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f <a href=\"https:\/\/github.com\/estet90\/platform-concept\/tree\/master\/gateway\" rel=\"noopener noreferrer nofollow\">API Gateway<\/a>, <a href=\"https:\/\/github.com\/estet90\/platform-concept\/tree\/master\/grpc-service\" rel=\"noopener noreferrer nofollow\">\u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 gRPC-\u0441\u0435\u0440\u0432\u0438\u0441<\/a> \u0438 <a href=\"https:\/\/github.com\/estet90\/platform-concept\/tree\/master\/proto-model\" rel=\"noopener noreferrer nofollow\">\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0441 nullable-\u0442\u0438\u043f\u0430\u043c\u0438<\/a>. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0438\u043c\u0435\u044e\u0449\u0438\u0435\u0441\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f, \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u0435\u043a\u0442 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043e\u0439 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0433\u043e API Gateway.<\/p>\n<h2>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u043e\u043d\u0443\u0441\u0430<\/h2>\n<h3>Hot reload<\/h3>\n<p>\u041e\u0434\u043d\u0438\u043c \u0438\u0437 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0431\u044b\u043b\u043e \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0431\u0435\u0437 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u042d\u0442\u043e \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430, \u0435\u0441\u043b\u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0432 \u0441\u0430\u043c\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 (\u043a\u0430\u043a \u0441\u0435\u0439\u0447\u0430\u0441), \u043d\u043e \u0435\u0441\u043b\u0438 \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u0411\u0414\/\u043a\u044d\u0448\u0435\/\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0441\u0445\u0435\u043c, \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f. \u0423 \u043c\u0435\u043d\u044f \u044d\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0437\u0430 \u0441\u0447\u0451\u0442 \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f <code>io.vertx.ext.web.Route<\/code>.<\/p>\n<details class=\"spoiler\">\n<summary>\u041d\u043e\u0432\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0432 MainHandler<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public void refreshHandle(RoutingContext routingContext) {     var contract = ofNullable(routingContext.getBody())             .map(Buffer::getBytes)             .map(bytes -> new String(bytes, StandardCharsets.UTF_8))             .orElseThrow();     var newGraphQl = GraphQlFactory.graphQl(mainResolver::resolve, contract);     var newGraphQlHandler = GraphQLHandler.create(newGraphQl, graphQlHandlerOptions);     router.getRoutes().stream()             .filter(route -> GRAPHQL_ROUTE_PATH.equals(route.getName()))             .findFirst()             .orElseThrow()             .remove();     router.post(GRAPHQL_ROUTE_PATH)             .handler(newGraphQlHandler);     routingContext.response().end(\"OK\"); }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0415\u0433\u043e \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u043a URI \/refresh<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@ApplicationScoped public Router router(Vertx vertx, MainHandler mainHandler) {     var router = Router.router(vertx);     var bodyHandler = BodyHandler.create();     router.post().handler(bodyHandler);     router.post(GRAPHQL_ROUTE_PATH)             .handler(mainHandler::graphqlHandle);     router.post(\"\/refresh\")             .handler(mainHandler::refreshHandle);     return router; }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041d\u043e\u0432\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438.<\/p>\n<h3>\u041a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0430<\/h3>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u0444\u0440\u043e\u043d\u0442\u0430 \u0434\u0435\u043b\u0430\u043b\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0430. \u0418 \u0445\u043e\u0442\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043e\u043d \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e, \u043d\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430 \u0434\u0435\u043b\u0430\u0442\u044c \u0435\u0433\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u0442.\u043a. \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0435\u0447\u0430\u0441\u0442\u043e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0442\u0432\u0435\u0442 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u0414\u043b\u044f \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u044f \u0432\u0437\u044f\u043b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/quarkus.io\/guides\/cache\" rel=\"noopener noreferrer nofollow\">quarkus-cache<\/a>, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0443\u044e <a href=\"https:\/\/github.com\/ben-manes\/caffeine\" rel=\"noopener noreferrer nofollow\">Caffeine<\/a>.<\/p>\n<details class=\"spoiler\">\n<summary>\u041d\u043e\u0432\u0430\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0432 build.gradle<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">implementation(\"io.quarkus:quarkus-cache\")<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0412\u044b\u0437\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public Uni&lt;Descriptors.FileDescriptor> serverReflectionInfo(String serverName, String serviceName) {     var serviceKey = new ServiceKey(serverName, serviceName);     return serverReflectionInfo(serviceKey); }  @CacheResult(cacheName = \"server-reflection-info\") Uni&lt;Descriptors.FileDescriptor> serverReflectionInfo(@CacheKey ServiceKey serviceKey) {     var serverReflectionClient = reflectionClients.get(serviceKey.serverName);     var request = requestBuilder.build(serviceKey.serviceName);     return serverReflectionClient.serverReflectionInfo(request)             .map(fileDescriptorResolver::resolve); }  private record ServiceKey(String serverName, String serviceName) { }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043a\u044d\u0448\u0430 \u0432 application.yaml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"yaml\">quarkus:   cache:     caffeine:       server-reflection-info:         expire-after-write: 60S         maximum-size: 100<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0418\u043d\u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043a\u044d\u0448\u0430 \u043f\u0440\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public void refreshHandle(RoutingContext routingContext) {     invalidateCache().subscribe().asCompletionStage();     \/\/ \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 Route }  @CacheInvalidateAll(cacheName = \"server-reflection-info\") Uni&lt;Void> invalidateCache() {     return Uni.createFrom().voidItem(); }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043a\u044d\u0448\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 Uni, \u043a\u044d\u0448\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0438\u043c\u0435\u043d\u043d\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442. \u041f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043f\u043e \u0442\u043e\u043c\u0443 \u0436\u0435 \u043a\u043b\u044e\u0447\u0443 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 gRPC-\u0441\u0435\u0440\u0432\u0438\u0441 \u0437\u0430 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u043e\u043c \u0443\u0436\u0435 \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f. \u0415\u0441\u043b\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043a \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0443, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043d\u0435 \u043a\u044d\u0448\u0438\u0440\u0443\u0435\u0442\u0441\u044f.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/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\/post\/662594\/\"> https:\/\/habr.com\/ru\/post\/662594\/<\/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<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>API Gateway \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c. \u041e\u043d \u043c\u043e\u0436\u0435\u0442 \u0440\u0435\u0448\u0430\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438:<\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u0432 \u0440\u0430\u0437\u043d\u044b\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u0430\u0445. \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043d\u0438\u043c.<\/p>\n<\/li>\n<li>\n<p>\u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433.<\/p>\n<\/li>\n<li>\n<p>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0410\u0433\u0440\u0435\u0433\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 (\u043e\u0434\u0438\u043d \u0437\u0430\u043f\u0440\u043e\u0441 \u043a API Gateway &#8212; \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0431\u044d\u043a\u0443).<\/p>\n<\/li>\n<li>\n<p>\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0418 \u043c\u043d\u043e\u0433\u043e\u0435 \u0434\u0440\u0443\u0433\u043e\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 API Gateway \u0432\u0441\u0435 \u044d\u0442\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u043b\u043e\u0436\u0430\u0442\u0441\u044f \u043d\u0430 \u0431\u044d\u043a\u0435\u043d\u0434. \u0418 \u0435\u0441\u043b\u0438 \u0434\u043b\u044f \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u043f\u0440\u0430\u0432\u0434\u0430\u043d\u043e, \u0442\u043e \u0432 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445 \u043b\u044e\u0431\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0431\u0449\u0435\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u043f\u043e\u0432\u043b\u0435\u0447\u0451\u0442 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0432\u0441\u0435\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432.<\/p>\n<p>\u0415\u0441\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0445 \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439, \u0432 \u0442.\u0447. \u0438 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u0435\u0439\u0441\u0430 (GraphQL &lt;-> gRPC), \u043d\u043e \u043d\u0438 \u043e\u0434\u043d\u043e \u0438\u0437 \u043d\u0438\u0445 \u043d\u0435 \u043f\u043e\u0434\u043e\u0448\u043b\u043e \u043d\u0430\u043c \u0432 \u043f\u043e\u043b\u043d\u043e\u0439 \u043c\u0435\u0440\u0435.<\/p>\n<h2>\u041f\u043e\u0447\u0435\u043c\u0443 GraphQL<\/h2>\n<p>\u041d\u0430 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 API Gateway \u043d\u0443\u0436\u0435\u043d \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441 \u0444\u0440\u043e\u043d\u0442\u0430. \u041a\u043e\u0433\u0434\u0430 \u043c\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u043b\u0438, \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0432\u0438\u0434\u043e\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0431\u044b\u043b REST. \u041e\u043d \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442 \u0434\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043d\u043e \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430\u0447\u0430\u043b\u0438 \u043f\u0440\u043e\u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0435\u0433\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438:<\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0443\u0436\u043d\u043e \u043f\u0430\u0440\u0443 \u043f\u043e\u043b\u0435\u0439, \u043c\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u043b\u0438 \u0432\u0435\u0441\u044c \u043e\u0431\u044a\u0435\u043a\u0442. \u0414\u0430, \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 PATCH \u0438 \u043f\u0430\u0440\u0441\u0438\u0442\u044c \u043d\u0430 \u0431\u044d\u043a\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044f, \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043e \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c null \u0438 \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u0435 \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043e, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0434\u043b\u044f REST.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043d\u0443\u0436\u043d\u044b \u0432\u0441\u0435 \u043f\u043e\u043b\u044f. \u041c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0432\u043c\u0435\u0441\u0442\u043e \u043e\u0434\u043d\u043e\u0433\u043e, \u043d\u043e \u0442\u043e\u0433\u0434\u0430 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u0435\u0439\u0441\u0430 \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434. \u0410 \u0435\u0441\u043b\u0438 \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0439 \u0438 \u0442\u043e\u0439 \u0436\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0440\u043e\u043b\u044f\u043c\u0438 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0437\u043d\u044b\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u044b \u043a \u043f\u043e\u043b\u044f\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435, \u043a \u0442\u043e\u043c\u0443 \u0436\u0435, \u043c\u043e\u0433\u0443\u0442 \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f REST, \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0442 \u043f\u0430\u043a\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0444\u0440\u043e\u043d\u0442 \u0434\u0435\u043b\u0430\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b.<\/p>\n<\/li>\n<\/ul>\n<p>GraphQL, <a href=\"https:\/\/habr.com\/ru\/post\/425041\/\" rel=\"noopener noreferrer nofollow\">\u0445\u043e\u0442\u044c \u0438 \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438<\/a>, \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0440\u0435\u0448\u0430\u0435\u0442 \u044d\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u043e\u043d\u0443\u0441\u0430 \u0432 GraphQL \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 REST \u0435\u0441\u0442\u044c <a href=\"https:\/\/graphql.org\/learn\/queries\/#directives\" rel=\"noopener noreferrer nofollow\">\u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u044b<\/a>. \u0418\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u0451\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0434\u043b\u044f \u043f\u043e\u043b\u0435\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0438\u043c\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0438 \u043f\u0440\u043e\u0447\u0435\u0435.<\/p>\n<h2>\u041f\u043e\u0447\u0435\u043c\u0443 gRPC<\/h2>\n<p>\u0421 API \u0434\u043b\u044f \u0444\u0440\u043e\u043d\u0442\u0430 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043d\u0430 \u0431\u044d\u043a. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u0442\u0435 \u0436\u0435, \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043f\u0430\u043a\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u043d\u0430 \u0431\u044d\u043a\u0435 \u0442\u0430\u043a\u0438\u0445 \u043a\u0435\u0439\u0441\u043e\u0432 \u043d\u0435\u0442 \u0438 \u043d\u0435 \u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0438\u0442\u0441\u044f). \u041c\u043e\u0436\u043d\u043e \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c API \u0431\u044d\u043a\u0430 \u043d\u0430 GraphQL, \u044d\u0442\u043e \u0431\u044b \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u043b\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 API Gateway. \u041d\u043e \u043d\u0435 \u0432\u0441\u0451 \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e. <\/p>\n<p>\u041c\u044b \u043f\u0438\u0448\u0435\u043c \u043d\u0430 Java, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <a href=\"https:\/\/quarkus.io\" rel=\"noopener noreferrer nofollow\">Quarkus<\/a>, \u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 GraphQL \u0442\u0430\u043c \u0435\u0441\u0442\u044c \u043d\u0435\u043f\u043b\u043e\u0445\u0438\u0435 \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043a\u0430\u043a \u0434\u043b\u044f <a href=\"https:\/\/quarkus.io\/guides\/smallrye-graphql\" rel=\"noopener noreferrer nofollow\">\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438<\/a>, \u0442\u0430\u043a \u0438 \u0434\u043b\u044f <a href=\"https:\/\/quarkus.io\/guides\/smallrye-graphql-client\" rel=\"noopener noreferrer nofollow\">\u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432<\/a>. \u0421 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043d\u0435\u0442, \u043d\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0430\u044f \u0434\u0430\u043b\u0435\u043a\u0430 \u043e\u0442 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0441\u0442\u0432\u0430.<\/p>\n<p><a href=\"https:\/\/quarkus.io\/guides\/smallrye-graphql-client#using-the-typesafe-client\" rel=\"noopener noreferrer nofollow\">Typesafe-\u043a\u043b\u0438\u0435\u043d\u0442<\/a> \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442 \u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u0435\u043d.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0440<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">\/\/\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 @GraphQLClientApi(configKey = \"star-wars-typesafe\") public interface StarWarsClientApi {      FilmConnection allFilms();  }  \/\/\u043f\u0440\u0438\u043c\u0435\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 public class StarWarsResource {     @Inject     StarWarsClientApi typesafeClient;      public FilmConnection getAllFilms() {         return typesafeClient.allFilms();     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u0442\u0430\u043a\u043e\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0435 \u0434\u0430\u0451\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u0435\u043b\u0430\u0442\u044c \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u043e\u043b\u044f \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<p><a href=\"https:\/\/quarkus.io\/guides\/smallrye-graphql-client#using-the-dynamic-client\" rel=\"noopener noreferrer nofollow\">Dynamic-\u043a\u043b\u0438\u0435\u043d\u0442<\/a> \u043e\u0447\u0435\u043d\u044c \u0433\u0438\u0431\u043a\u0438\u0439. \u041c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0439 \u0443\u0433\u043e\u0434\u043d\u043e \u043d\u0430\u0431\u043e\u0440 \u043f\u043e\u043b\u0435\u0439, \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/graphql.org\/learn\/queries\/#variables\" rel=\"noopener noreferrer nofollow\">\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435<\/a>, \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432 \u043e\u0442\u0432\u0435\u0442\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0440<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public class StarWarsResource {      @Inject     @GraphQLClient(\"star-wars-dynamic\")     DynamicGraphQLClient dynamicClient;          public FilmConnection getAllFilmsUsingDynamicClient() {         Document query = document(                 operation(                         field(\"allFilms\",                                 field(\"films\",                                         field(\"title\"),                                         field(\"planetConnection\",                                                 field(\"planets\",                                                         field(\"name\")                                                 )                                         )                                 )                         )                 )         );         Response response = dynamicClient.executeSync(query);         return response.getObject(FilmConnection.class, \"allFilms\");     }  }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041d\u043e \u044d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u0433\u0440\u043e\u043c\u043e\u0437\u0434\u043a\u043e. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435 \u043f\u0440\u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0443.<\/p>\n<p>\u0412 gRPC \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u044b. \u0410 \u0434\u043b\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0432 \u043e\u0442\u0432\u0435\u0442, \u0435\u0441\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0442\u0438\u043f &#8212; <a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/reference\/csharp\/class\/google\/protobuf\/well-known-types\/field-mask\" rel=\"noopener noreferrer nofollow\">FieldMask<\/a>.<\/p>\n<p>\u0412 gRPC \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432-\u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f protobuf. \u0415\u0433\u043e \u0436\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u043b\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438 \u0447\u0435\u0440\u0435\u0437 kafka. \u0422.\u043e. \u043d\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u043b\u043e\u0434\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442\u044b, \u0438 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0431\u044d\u043a\u0435 \u0447\u0442\u043e-\u0442\u043e \u043e\u0434\u043d\u043e.<\/p>\n<p>\u0427\u0430\u0441\u0442\u043e, \u043a\u043e\u0433\u0434\u0430 \u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u043e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430\u0445 gRPC, \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u044e\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0441\u043d\u0438\u0436\u0430\u044e\u0449\u0435\u0439 \u043d\u0430\u043a\u043b\u0430\u0434\u043d\u044b\u0435 \u0440\u0430\u0441\u0445\u043e\u0434\u044b. \u041c\u044b \u043a \u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u043a\u0430 \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u0438, \u043d\u043e \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c.<\/p>\n<p>\u0412 protobuf \u0435\u0441\u0442\u044c <a href=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/546182\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0441 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 null-\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439<\/a>, \u043d\u043e \u0435\u0451 \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043f\u043e-\u0441\u0432\u043e\u0435\u043c\u0443 (\u043e\u0431 \u044d\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u0434\u0430\u043b\u0435\u0435).<\/p>\n<h2>\u0413\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f<\/h2>\n<p>\u0420\u0430\u043d\u0435\u0435 \u044f \u043f\u0438\u0441\u0430\u043b, \u0447\u0442\u043e \u043d\u0430 \u0431\u044d\u043a\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c Java \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043d\u0430\u0439\u0442\u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u0433\u043e\u0442\u043e\u0432\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u043d\u0451\u043c. \u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435, \u0447\u0442\u043e \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0439\u0442\u0438, \u044d\u0442\u043e \u043f\u0440\u043e\u0435\u043a\u0442 <a href=\"https:\/\/rejoiner.io\/\" rel=\"noopener noreferrer nofollow\">Rejoiner<\/a>. \u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u043a\u043e\u0440\u043e\u0431\u043e\u0447\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430 \u043d\u0443\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u0447\u0442\u043e \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e, \u0442.\u043a. \u043f\u0440\u0438 \u0435\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438\/\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442. \u0415\u0449\u0451 \u043e\u0434\u0438\u043d \u043c\u0438\u043d\u0443\u0441 &#8212; \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0435 \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0435\u0442\u0441\u044f. \u041e\u0434\u043d\u0430\u043a\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u0432 \u0435\u0433\u043e \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u0445 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0447\u0435\u0440\u043f\u043d\u0443\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e API Gateway.<\/p>\n<p>\u0415\u0449\u0451 \u043e\u0434\u0438\u043d \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 &#8212; <a href=\"https:\/\/www.graphql-mesh.com\/\" rel=\"noopener noreferrer nofollow\">GraphQL Mesh<\/a> &#8212; \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 TypeScript \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 \u0438\u0437 GraphQL \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 gRPC, \u043d\u043e \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f. \u041d\u043e \u043e\u043d \u043d\u0435 \u0434\u0430\u0451\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u0442\u0438\u043f\u043e\u0432 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u0432\u043e\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u0412\u0441\u0451 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0430\u043c\u0438\u043c, \u043d\u043e \u043f\u0438\u0448\u0435\u043c \u043c\u044b \u043d\u0430 Java.<\/p>\n<p>\u0415\u0441\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0430 Go, \u043d\u043e \u043e\u043d\u0438 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e API Gateway \u0438\u0437 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430, \u0447\u0442\u043e \u043d\u0430\u0441 \u043d\u0435 \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442. \u0412 \u0438\u0442\u043e\u0433\u0435 \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 API Gateway \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0441\u0442\u044d\u043a\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439.<\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h2>\n<p>\u0421\u043f\u0438\u0441\u043e\u043a \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043a \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443:<\/p>\n<ul>\n<li>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 Java\/Quarkus.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043a\u043e\u0434\u043e\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 DTO \u0438 \u0441\u0442\u0430\u0431\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u043e\u0441\u043b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f API \u043a\u0430\u043a\u043e\u0433\u043e-\u043b\u0438\u0431\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c &#171;\u0433\u043e\u0440\u044f\u0447\u0435\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f&#187; \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430. \u041f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430 \u0431\u044d\u043a\u0435 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u0434 API Gateway.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 batch-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<h3>\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/h3>\n<details class=\"spoiler\">\n<summary>build.gradle<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">ext {         quarkusVersion = \"2.7.4.Final\"         graphqlVersion = \"17.0\"         lombokVersion = \"1.18.22\" }  dependencies {     implementation(             platform(\"io.quarkus:quarkus-bom:$quarkusVersion\"),             \"io.quarkus:quarkus-config-yaml\",             \"io.quarkus:quarkus-grpc-common\",             \"io.quarkus:quarkus-grpc-stubs\",             \"com.graphql-java:graphql-java-extended-scalars:$graphqlVersion\",             \"com.graphql-java:graphql-java-extended-validation:$graphqlVersion\",             \"io.vertx:vertx-web-graphql\",             \"com.google.protobuf:protobuf-java-util\",             \"com.fasterxml.jackson.core:jackson-databind\",     )     compileOnly(\"org.projectlombok:lombok:$lombokVersion\")     annotationProcessor(\"org.projectlombok:lombok:$lombokVersion\") }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><code>quarkus-...<\/code> &#8212; \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 YAML-\u043a\u043e\u043d\u0444\u0438\u0433\u043e\u043c \u0438 gRPC.<br \/><code>graphql-java-extended-scalars<\/code> &#8212; \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043a\u0430\u043b\u044f\u0440\u044b GraphQL. \u0418\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0435 \u0442\u0430\u043a \u043c\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u043e\u0432, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0435 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c.<br \/><code>graphql-java-extended-validation<\/code> &#8212; \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u044b \u0434\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<br \/><code>protobuf-java-util<\/code> &#8212; \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432-\u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043e\u0442 gRPC-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON.<br \/><code>jackson-databind<\/code> &#8212; \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0433\u043e \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON.<br \/><code>lombok<\/code> &#8212; \u043f\u0435\u0440\u0447\u0438\u043a.<br \/><code>vertx-web-graphql<\/code> &#8212; \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 GraphQL \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e&#8230; Vertx.<\/p>\n<p>\u0425\u043e\u0442\u044f Quarkus \u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c \u0434\u043b\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u043e \u043e\u043d, \u043a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0431\u043e\u043b\u044c\u0448\u0435 \u0437\u0430\u0442\u043e\u0447\u0435\u043d \u043d\u0430 \u043f\u043e\u0434\u0445\u043e\u0434 code-first, \u0430 \u043c\u044b \u0441\u0442\u0440\u043e\u0433\u043e \u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u0434\u0445\u043e\u0434\u0430 contract-first. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435 \u043f\u0440\u0438 \u043f\u043e\u0434\u0445\u043e\u0434\u0435 code-first \u043d\u0430\u043c \u0431\u044b \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442 Quarkus \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0431\u0443\u0434\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e DI, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a gRPC-\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c. \u0410 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 Vertx.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0443 Quarkus \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f Vertx, \u0447\u0442\u043e \u0431\u044b\u0432\u0430\u0435\u0442 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0445 \u0432\u0435\u0449\u0435\u0439. \u0421\u0435\u0440\u0432\u0435\u0440\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c Quarkus \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 Vertx, \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 REST\/GraphQL \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 HTTP-\u043a\u043b\u0438\u0435\u043d\u0442 \u0438\u0437 Vertx, \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0411\u0414 \u0438\u0434\u0451\u0442 \u0447\u0435\u0440\u0435\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Vertx. \u041e\u0434\u043d\u0430\u043a\u043e \u043d\u0435 \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0435\u0441\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0432 Vertx, \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 Quarkus. \u0421\u0435\u0440\u0432\u0435\u0440\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0434\u043b\u044f GraphQL \u0438 \u043e\u0431\u0451\u0440\u0442\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 gRPC \u0432 Quarkus \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Vertx.<\/p>\n<\/div>\n<\/details>\n<h3>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<\/h3>\n<p>\u041a\u0430\u043a \u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c GraphQL, \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 <a href=\"https:\/\/vertx.io\/docs\/vertx-web-graphql\/java\/\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 Vertx<\/a> \u0438 <a href=\"https:\/\/www.graphql-java.com\/documentation\/getting-started\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 graphql-java<\/a>. \u0412 \u0438\u0442\u043e\u0433\u0435 \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u0442\u0430\u043a\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f:<\/p>\n<details class=\"spoiler\">\n<summary>\u0424\u0430\u0431\u0440\u0438\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f GraphQL<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">package ru.craftysoft.platform.gateway.configuration;  import graphql.GraphQL; import graphql.language.FieldDefinition; import graphql.language.ObjectTypeDefinition; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import graphql.schema.idl.SchemaGenerator; import graphql.schema.idl.SchemaParser; import graphql.schema.idl.TypeDefinitionRegistry; import graphql.schema.idl.TypeRuntimeWiring; import graphql.validation.constraints.standard.SizeConstraint; import graphql.validation.rules.OnValidationErrorStrategy; import graphql.validation.rules.ValidationRules; import graphql.validation.schemawiring.ValidationSchemaWiring; import io.vertx.core.Future; import io.vertx.ext.web.handler.graphql.schema.VertxDataFetcher; import lombok.NoArgsConstructor;  import java.util.Collection; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors;  import static graphql.scalars.ExtendedScalars.*; import static<\/code><\/pre>\n<\/div>\n<\/details>\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-332323","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/332323","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=332323"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/332323\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=332323"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=332323"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=332323"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}