{"id":327257,"date":"2022-01-10T08:49:21","date_gmt":"2022-01-10T08:49:21","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=327257"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=327257","title":{"rendered":"<span>React Apollo, Gqlgen \u2013 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f. \u0427\u0430\u0441\u0442\u044c 1<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\" class=\"article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" height=\"629\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/623\/a46\/b5c\/623a46b5c3365f0c205a7c55630ce325.png\" data-width=\"1400\"\/><figcaption><\/figcaption><\/figure>\n<p>\u042d\u0442\u043e \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0435\u0435 \u0441\u0445\u0435\u043c\u0443 \u0440\u0430\u0431\u043e\u0442\u044b &#171;\u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0439&#187; \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u041f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u0430\u0432\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0432\u044b\u0434\u0430\u044e\u0442\u0441\u044f \u0441 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e.<\/p>\n<h2>\u0417\u0430\u0434\u0430\u0447\u0430<\/h2>\n<p>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c\u0441\u044f &#171;\u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c&#187; \u043e\u0431\u0440\u0430\u0437\u043e\u043c: \u043a\u043e\u0434 \u0432 \u0421\u041c\u0421 \u043b\u0438\u0431\u043e \u043a\u043e\u0434 \u0432 URL. \u041f\u0430\u0440\u043e\u043b\u044c \u0443 user \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442.<\/p>\n<h3>\u041a\u0435\u0439\u0441<\/h3>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432 \u0444\u043e\u0440\u043c\u0435 \u0432\u0445\u043e\u0434\u0430 \u0432\u0432\u043e\u0434\u0438\u0442 \u0441\u0432\u043e\u0439 Username, \u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043c\u0435\u0442\u043e\u0434\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442:<\/p>\n<ul>\n<li>\n<p>\u041f\u0438\u0441\u044c\u043c\u043e \u0441 <strong>\u043a\u043d\u043e\u043f\u043a\u043e\u0439<\/strong> \u043d\u0430 \u0435\u043c\u0430\u0439\u043b, \u043f\u0440\u0438 \u0435\u0435 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 \u2013 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f. \u041f\u043e\u0447\u0442\u043e\u0432\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0444\u043e\u0440\u043c\u0430 \u0432\u0432\u043e\u0434\u0430 \u043a\u043e\u0434\u0430 \u0438\u0437 \u0421\u041c\u0421, \u043f\u0440\u0438 \u0443\u0441\u043f\u0435\u0445\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u0442\u0441\u044f<\/p>\n<\/li>\n<\/ul>\n<h3>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430<\/h3>\n<p>\u041c\u044b \u043d\u0435 \u0437\u043d\u0430\u0435\u043c \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c <strong>\u043d\u0430\u0436\u043c\u0435\u0442 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443<\/strong>. \u041d\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0435\u0435 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043d\u044f\u0442\u044c \u0447\u0442\u043e \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c HTTP \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u043e\u043a\u0435\u043d. <\/p>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0441\u0435\u0441\u0441\u0438\u0438 \u043f\u043e \u043f\u0440\u0435\u0434\u044c\u044f\u0432\u043b\u0435\u043d\u0438\u044e \u2013 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 <code>ClientID<\/code>. <\/p>\n<h3>\u041a\u0430\u043a \u0440\u0435\u0448\u0430\u0442\u044c?<\/h3>\n<ol>\n<li>\n<p>\u041f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 <s>\u0431\u0440\u0430\u0443\u0437\u0435\u0440<\/s> <strong>\u041a\u043b\u0438\u0435\u043d\u0442<\/strong> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 cookie c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c <code>ClientID<\/code> <\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435 <strong>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c<\/strong> \u0444\u043e\u0440\u043c\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043a\u0435\u043d \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 <code>Auth_token<\/code> \u2013 \u043e\u0431\u043c\u0435\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0442\u043e\u043a\u0435\u043d <strong>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/strong><\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u0441\u0435\u0441\u0441\u0438\u044f, \u0445\u0440\u0430\u043d\u0438\u0442 <code>Auth_token<\/code> , <code>ClientID<\/code> \u0438 <code>UserID<\/code><\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c<\/strong> \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0435\u0442 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e. \u0418\u0449\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043f\u043e <code>ClientID<\/code> \u0432 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f\u0445 websocket \u2013 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u0438\u0433\u043d\u0430\u043b \u043e\u0431 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p><strong>\u041a\u043b\u0438\u0435\u043d\u0442<\/strong> \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0441\u0438\u0433\u043d\u0430\u043b \u043e \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f GET-\u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u0442\u043e\u043a\u0435\u043d\u043e\u043c <code>Auth_token<\/code> \u0432 HTTP-\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 Authorization. \u0418\u0449\u0435\u043c <code>Auth_token<\/code> \u0432 \u0441\u0435\u0441\u0441\u0438\u044f\u0445, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0445\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u043c <strong>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/strong><\/p>\n<\/li>\n<\/ol>\n<blockquote>\n<p>\u0421\u0442\u0430\u0442\u044c\u044f \u0440\u0430\u0437\u0431\u0438\u0442\u0430 \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0447\u0430\u0441\u0442\u0435\u0439:<br \/>&#8212; <a href=\"https:\/\/habr.com\/ru\/post\/599723\/\" rel=\"noopener noreferrer nofollow\">\u0447\u0430\u0441\u0442\u044c 2<\/a><br \/>&#8212; \u0447\u0430\u0441\u0442\u044c 3 &#8212; \u0432 \u0440\u0430\u0431\u043e\u0442\u0435<br \/>&#8212; <a href=\"https:\/\/github.com\/zhivulinal\/react-apollo-gqlgen-tutorial\/tree\/f34c72e0d9029f6d77966c3797810f38c6bf9f08\" rel=\"noopener noreferrer nofollow\">\u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438<\/a><\/p>\n<\/blockquote>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h3>\n<ol>\n<li>\n<p>\u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c <a href=\"https:\/\/gqlgen.com\/getting-started\/\" rel=\"noopener noreferrer nofollow\">Gqlgen<\/a><\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c <a href=\"https:\/\/graphql.org\/learn\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0445\u0435\u043c\u044b GraphQL<\/a>, \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0410\u041f\u0418<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c CORS<\/p>\n<\/li>\n<li>\n<p>GraphQL \u0441\u0435\u0440\u0432\u0435\u0440<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c websocket \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>Store<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a<\/p>\n<\/li>\n<\/ol>\n<h3>1. \u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c Gqlgen<\/h3>\n<p><a href=\"https:\/\/www.google.com\/search?q=Gqlgen+how+use&amp;rlz=1C5CHFA_enRU904RU904&amp;oq=Gqlgen+how+use&amp;aqs=chrome..69i57j0i333.7285j0j7&amp;sourceid=chrome&amp;ie=UTF-8\" rel=\"noopener noreferrer nofollow\">\u0421\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 Gqlgen<\/a> \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435 \u043c\u0430\u043b\u043e. \u041c\u044b \u0432\u044b\u0431\u0440\u0430\u043b\u0438 \u0442\u043e\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u043c \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u043c.<\/p>\n<h4>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:<\/h4>\n<ul>\n<li>\n<p><code>\/backoffice\/cmd<\/code>\u00a0\u2013 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b<\/p>\n<\/li>\n<li>\n<p><code>\/backoffice\/graph<\/code>\u00a0\u2013 \u0444\u0430\u0439\u043b\u044b GraphQL<\/p>\n<\/li>\n<li>\n<p><code>\/backoffice\/schema<\/code>\u00a0\u2013 GraphQL \u0441\u0445\u0435\u043c\u044b<\/p>\n<\/li>\n<li>\n<p><code>\/backoffice\/models<\/code>\u00a0\u2013 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 GraphQL<\/p>\n<\/li>\n<li>\n<p><code>\/backoffice\/pkg<\/code>\u00a0\u2013 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>backoffice<\/code>, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c:<\/p>\n<pre><code class=\"bash\">go mod init react-apollo-gqlgen-tutorial\/backoffice go get github.com\/99designs\/gqlgen go run github.com\/99designs\/gqlgen init<\/code><\/pre>\n<p>\u041e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b gqlgen.yml:<\/p>\n<pre><code class=\"yaml\"># \u0418\u0437\u043c\u0435\u043d\u0438\u043c \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0444\u0430\u0439\u043b\u043e\u0432 \u0441\u0445\u0435\u043c\u044b schema:   - schema\/*.graphqls  # \u0418\u0437\u043c\u0435\u043d\u0438\u043c \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 model:   filename: models\/models_gen.go   package: model    # \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 # \u0427\u0442\u043e\u0431\u044b \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043d\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u0442\u0438\u0440\u0430\u043b \u0443\u0436\u0435 \u0438\u043c\u0435\u044e\u0449\u0435\u0435\u0441\u044f autobind:   - \"react-apollo-gqlgen-tutorial\/backoffice\/models\"<\/code><\/pre>\n<p>\u041f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u0443\u0435\u043c \u0444\u0430\u0439\u043b <code>server.go<\/code> \u0432 <code>main.go<\/code> \u0438 \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u043c \u0435\u0433\u043e \u0432\u00a0<code>\/backoffice\/cmd<\/code>.<\/p>\n<p>\u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438\u00a0<code>\/backoffice\/cmd<\/code> \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <code>gqlgen.go<\/code>:<\/p>\n<blockquote>\n<p>\/\/ +build tools \u2013 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439, <a href=\"https:\/\/github.com\/golang\/go\/wiki\/Modules#how-can-i-track-tool-dependencies-for-a-module\" rel=\"noopener noreferrer nofollow\">\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0437\u0434\u0435\u0441\u044c<\/a><\/p>\n<\/blockquote>\n<pre><code class=\"go\">\/\/ +build tools  package main  import ( \"fmt\" \"github.com\/99designs\/gqlgen\/cmd\" )  func main() { fmt.Println(\"Building Graphql schema\") cmd.Execute() }<\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u0438 \u0438\u0437 \u0441\u0445\u0435\u043c\u044b GraphQL \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u044b:<\/p>\n<pre><code class=\"bash\">go run cmd\/gqlgen.go<\/code><\/pre>\n<h3>2. \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0441\u0445\u0435\u043c\u044b GraphQL, \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0410\u041f\u0418<\/h3>\n<p>\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c 3 \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0445: <code>Auth<\/code>, <code>Session<\/code>, <code>User<\/code> \u0438 \u043c\u0435\u0442\u043e\u0434\u044b GraphQL.<\/p>\n<p>Schema <code>schema\/schema.graphqls<\/code>:<\/p>\n<pre><code class=\"dart\">\"\"\" \u0417\u0430\u043f\u0440\u043e\u0441\u044b GET \"\"\" type Query {    \"\"\"   \u041f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438    \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0444\u043b\u0430\u0433\u0430 Auth.authorized      1. \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c Auth.auth_token \u0438 Auth.authorized   \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0435\u0433\u043e \u0432 HTTP \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 Authorization      2. \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c Auth.client_id   \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 Client-ID   \"\"\"   auth: Auth!    user: User! }  \"\"\" \u0417\u0430\u043f\u0440\u043e\u0441\u044b POST \"\"\" type Mutation {    \"\"\"   \u041c\u0435\u0442\u043e\u0434 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.   \u041f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 username   \u0412\u0435\u0440\u043d\u0435\u0442 Auth.auth_token, \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0432    HTTP \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 Authorization   \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f   \"\"\"   authorization(login: String!): Auth!   smsCode(code: String!): Auth! }  \"\"\" \u041f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 websocket \"\"\" type Subscription {    \"\"\"   \u041f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 \u043d\u0430 Auth   \"\"\"   auth: Auth! }<\/code><\/pre>\n<p>Session <code>schema\/session.graphqls<\/code>:<\/p>\n<pre><code class=\"dart\">type Session {      \"\"\"     \u0422\u043e\u043a\u0435\u043d \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0432\u043f\u0430\u0441\u0442\u044c \u0441 \u0442\u0435\u043c     \u0447\u0442\u043e \u043e\u0442\u0434\u0430\u043b\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u043f\u0440\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435 \u0444\u043e\u0440\u043c\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438     \"\"\"     auth_token: String!      \"\"\"     \u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     \"\"\"     uid:    Int!      \"\"\"     \u041c\u0435\u0442\u043e\u0434 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c     \"\"\"     method: String! }<\/code><\/pre>\n<p>Auth <code>schema\/auth.graphqls<\/code>:<\/p>\n<pre><code class=\"dart\">type Auth {      \"\"\"     \u0414\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u044a\u044f\u0432\u043b\u0435\u043d \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0442\u043e\u043a\u0435\u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u043d\u0430 GET \u0437\u0430\u043f\u0440\u043e\u0441 \u0444\u043e\u0440\u043c\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438      \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432 HTTP \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 Client-ID     \"\"\"     client_id:      String!      \"\"\"     \u0414\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u044a\u044f\u0432\u043b\u0435\u043d \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0442\u043e\u043a\u0435\u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u043d\u0430 GET \u0437\u0430\u043f\u0440\u043e\u0441 \u0444\u043e\u0440\u043c\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438      \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432 HTTP \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 Authorization     \"\"\"     token:      String!      \"\"\"     \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438     \"\"\"     authorized: Boolean!      \"\"\"     \u041c\u0435\u0442\u043e\u0434 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438     \"\"\"     method: String! }<\/code><\/pre>\n<p>\u041d\u0430 <code>User<\/code> \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/github.com\/zhivulinal\/react-apollo-gqlgen-tutorial\/blob\/6acbcfe4c9454aaa735ef0a1264820ae1af5cdf3\/backoffice\/schema\/user.graphqls\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a><\/p>\n<h3>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u0432<\/h3>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 \u0441\u0445\u0435\u043c GraphQL \u0431\u044b\u043b\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<pre><code class=\"bash\">go run cmd\/gqlgen.go<\/code><\/pre>\n<p>\u042d\u0442\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0441\u043e\u0437\u0434\u0430\u0441\u0442 <code>\/backoffice\/models<\/code>  \u043d\u043e \u043d\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>\/backoffice\/graph<\/code>. <\/p>\n<h4>backoffice\/graph:<\/h4>\n<ol>\n<li>\n<p>\u0423\u0434\u0430\u043b\u044f\u0435\u043c \u043f\u0430\u043f\u043a\u0443 models \u0432 <code>\/backoffice\/graph<\/code><\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0435\u043c \u0444\u0430\u0439\u043b\u044b: <code>resolver.go<\/code> \u0438 <code>schema.resolvers.go<\/code> \u0432  <code>\/backoffice\/pkg\/graph<\/code><\/p>\n<\/li>\n<\/ol>\n<h4>backoffice\/pkg\/qraph:<\/h4>\n<p>\u041e\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b <code>schema.resolvers.go<\/code> \u0437\u0430\u0431\u0435\u0440\u0435\u043c \u043c\u0435\u0442\u043e\u0434\u044b \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0438\u0435\u0441\u044f \u043a <code>*model.Auth<\/code> \u0438 <code>*model.User<\/code> . \u041f\u043e\u043c\u0435\u0441\u0442\u0438\u043c \u0438\u0445 \u0432 <code>auth.go<\/code> \u0438 <code>user.go<\/code> \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430<\/p>\n<p>\u0417\u0430\u0442\u044f\u043d\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<pre><code>go mod vendor<\/code><\/pre>\n<h4>\u041f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0430\u044f\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:<\/h4>\n<p><a href=\"https:\/\/github.com\/zhivulinal\/react-apollo-gqlgen-tutorial\/tree\/278f43d7d75f7c4d68e7c9572ef134d923e529b9\" rel=\"noopener noreferrer nofollow\">\u041a\u043e\u043c\u043c\u0438\u0442 Github<\/a><\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" height=\"930\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/84c\/703\/36f\/84c70336f98c593c194f47d7c6588594.png\" data-width=\"1120\"\/><figcaption><\/figcaption><\/figure>\n<h3>3. \u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c CORS<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u0437\u0430\u0449\u0438\u0442\u0443 \u043e\u0442 CSRF \u0430\u0442\u0430\u043a<\/p>\n<pre><code class=\"go\">func CorsMiddleware() func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {  \/\/ \u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 \u0445\u043e\u0441\u0442\u0443       \/\/ \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e \u0432\u0441\u0435\u0433\u0434\u0430 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0430\u0434\u0440\u0435\u0441 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0445\u043e\u0441\u0442\u0430       \/\/ \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u044f \u0437\u0432\u0435\u0437\u0434\u043e\u0447\u043a\u0443 \"*\" - \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 w.Header().Set(\"Access-Control-Allow-Origin\", \"http:\/\/localhost:3000\")  \/\/ \u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u043c \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b cookie \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442 http:\/\/localhost:3000 \/\/ \/\/ \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u044f \/\/ Access-Control-Allow-Origin \u0438 Access-Control-Allow-Credentials \/\/ \u0412 \u044d\u0442\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u0435: \/\/ https:\/\/fetch.spec.whatwg.org\/#cors-protocol-and-credentials w.Header().Set(\"Access-Control-Allow-Credentials\", \"true\")  \/\/ \u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u044b w.Header().Set(\"Access-Control-Allow-Methods\", \"POST, GET, OPTIONS, PUT, DELETE\")  \/\/ \u0411\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c CSRF \/\/ Access-Control-Allow-Headers = Content-Type \/\/ \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0437\u0434\u0435\u0441\u044c: \/\/ https:\/\/fetch.spec.whatwg.org\/#concept-header w.Header().Set(\"Access-Control-Allow-Headers\", \"Accept, Content-Type, Content-Length, Accept-Encoding, Authorization\")  if r.Method == \"OPTIONS\" { return }  next.ServeHTTP(w, r) }) } }<\/code><\/pre>\n<blockquote>\n<p>\u0414\u043b\u044f \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u043e\u0439 \u0437\u0430\u0449\u0438\u0442\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0440\u0430\u043d\u0438\u0442\u044c XSS-\u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0438. <br \/><a href=\"https:\/\/academind.com\/tutorials\/localstorage-vs-cookies-xss\" rel=\"noopener noreferrer nofollow\">\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0430 \u044d\u0442\u0443 \u0442\u0435\u043c\u0443<\/a> \u0430\u043d\u0433\u043b.<\/p>\n<\/blockquote>\n<h3>4. GraphQL \u0441\u0435\u0440\u0432\u0435\u0440<\/h3>\n<p>\u041c\u044b \u0443\u0436\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u043b\u0438 \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0444\u0430\u0439\u043b\u044b \u0432 <code>\/pkg\/qraph<\/code>. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c <code>resolver.go<\/code>:<\/p>\n<pre><code class=\"go\">var ( mb int64 = 1 &lt;&lt; 20 )  type Resolver struct{}  \/\/ \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e NewServer func NewServer(opt Options) *handler.Server {  \/\/ \u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438\u0437 cmd\/main.go srv := handler.New( generated.NewExecutableSchema( generated.Config{ Resolvers: &amp;Resolver{}, }, ), ) srv.AddTransport(transport.MultipartForm{ MaxMemory:     32 * mb, MaxUploadSize: 50 * mb, }) srv.AddTransport(transport.POST{}) srv.AddTransport(transport.GET{}) srv.AddTransport(transport.Websocket{ KeepAlivePingInterval: 10 * time.Second, Upgrader: websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, ReadBufferSize:  1024, WriteBufferSize: 1024, }, InitFunc: transport.WebsocketInitFunc(func(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) { return ctx, nil }), }) srv.Use(extension.Introspection{})  return srv }  type Options struct {}<\/code><\/pre>\n<h3>5. Websocket \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 <\/h3>\n<p>\u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 websocket \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/github.com\/gorilla\/websocket\" rel=\"noopener noreferrer nofollow\">Gorilla websocket<\/a> \u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 HTTP \u2013 <a href=\"https:\/\/github.com\/gorilla\/mux\" rel=\"noopener noreferrer nofollow\">Gorilla mux<\/a><\/p>\n<p>\u0418\u0437\u043c\u0435\u043d\u0438\u043c <code>cmd\/main.go<\/code>:<\/p>\n<pre><code class=\"go\">import (   \/\/...    \"react-apollo-gqlgen-tutorial\/backoffice\/pkg\/graph\" \"github.com\/gorilla\/mux\" )  var ( defaultPort = \"2000\" )  func main() { port := os.Getenv(\"PORT\") if port == \"\" { port = defaultPort }    \/\/ \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c GraphQL \u0441\u0435\u0440\u0432\u0435\u0440 srv := graph.NewServer(graph.Options{})  \/\/ \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0440\u043e\u0443\u0442\u0435\u0440 router := mux.NewRouter()  \/\/ \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c CORS middleware router.Use(middleware.CorsMiddleware())  router.Handle(\"\/\", playground.Handler(\"GraphQL playground\", \"\/graphql\")) router.Handle(\"\/graphql\", srv)  log.Printf(\"connect to http:\/\/localhost:%s\/ for GraphQL playground\", port) log.Fatal(http.ListenAndServe(\":\"+port, router)) }<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/zhivulinal\/react-apollo-gqlgen-tutorial\/tree\/4c1e24ce089f14b2831b241b4349a9ed19517154\" rel=\"noopener noreferrer nofollow\">\u041a\u043e\u043c\u043c\u0438\u0442 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u044d\u0442\u0430\u043f\u0430<\/a><\/p>\n<h3>6. Store <\/h3>\n<p>\u0412 \u043d\u0430\u0448\u0435\u0439 \u043b\u043e\u0433\u0438\u043a\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439:<\/p>\n<ol>\n<li>\n<p><code>Session<\/code>: \u0445\u0440\u0430\u043d\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0431 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0439 \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0441\u0435\u0441\u0441\u0438\u044f\u0445, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c<\/p>\n<\/li>\n<li>\n<p><code>Auth<\/code>: \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/p>\n<\/li>\n<li>\n<p><code>User<\/code>: \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c<\/p>\n<\/li>\n<\/ol>\n<p>Store \u043f\u043e \u0444\u0430\u043a\u0442\u0443 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u043e\u043c, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u043c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0449\u0438\u0435 \u043e\u0431\u0449\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443. <\/p>\n<p>\u041e\u043f\u0438\u0448\u0435\u043c Store <code>\/backoffice\/pkg\/store<\/code>:<\/p>\n<pre><code class=\"go\">package store  type Store struct { token TokenOptions }  func NewStore(opt Options) *Store { return &amp;Store{ token: opt.Token, } }  type Options struct { Token TokenOptions }  type TokenOptions struct {}<\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0435\u0442\u043e\u0434\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0430 GraphQL.<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b <code>Auth<\/code>:<\/p>\n<pre><code class=\"go\">\/\/ pkg\/store\/auth.go  \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 Auth \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 func (s *Store) Auth(ctx context.Context) (auth *model.Auth, err error) { \/\/ ... return }  \/\/ \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u0442 websocket, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043a\u0430\u043d\u0430\u043b func (s *Store) AuthCreateWebsocket(ctx context.Context) (out &lt;-chan *model.Auth, err error) { \/\/ ... return }  \/\/ \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043e Username func (s *Store) AuthorizeForUsername(ctx context.Context, login string) (auth *model.Auth, err error) { \/\/ ... return }  \/\/ \u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0437 \u0421\u041c\u0421 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f func (s *Store) AuthSMSApprove(ctx context.Context, code string) (auth *model.Auth, err error) { \/\/ ... return }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b <code>User<\/code>:<\/p>\n<pre><code class=\"go\">\/\/ pkg\/store\/user.go  \/\/ \u0412\u0435\u0440\u043d\u0435\u0442 User \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 func (s *Store) User(ctx context.Context) (user *model.User, err error) { \/\/ ... return }<\/code><\/pre>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c <code>Store<\/code> \u0432 <code>pkg\/graph\/resolver.go<\/code>:<\/p>\n<pre><code class=\"go\">type Resolver struct{ store *store.Store }  func NewServer(opt Options) *handler.Server { srv := handler.New( generated.NewExecutableSchema( generated.Config{ Resolvers: &amp;Resolver{ store: opt.Store, }, }, ), )   \/\/ ... }  type Options struct { Store *store.Store }<\/code><\/pre>\n<p>\u041e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c <code>pkg\/graph\/auth.go<\/code> \u0438 <code>pkg\/graph\/user.go<\/code><\/p>\n<pre><code class=\"go\">\/\/ pkg\/graph\/auth.go func (r *queryResolver) Auth(ctx context.Context) (*model.Auth, error) { return r.store.Auth(ctx) }  func (r *subscriptionResolver) Auth(ctx context.Context) (&lt;-chan *model.Auth, error) { return r.store.AuthCreateWebsocket(ctx) }  func (r *mutationResolver) Authorization(ctx context.Context, login string) (*model.Auth, error) { return r.store.AuthorizeForUsername(ctx, login) }  func (r *mutationResolver) SmsCode(ctx context.Context, code string) (*model.Auth, error) { return r.store.AuthSMSApprove(ctx, code) }  \/\/ pkg\/graph\/user.go func (r *queryResolver) User(ctx context.Context) (*model.User, error) { return r.store.User(ctx) }<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/zhivulinal\/react-apollo-gqlgen-tutorial\/tree\/4bd178e1a9b67fb4048ab70dc1c6b3a70654d382\" rel=\"noopener noreferrer nofollow\">\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u044d\u0442\u0430\u043f\u0430<\/a><\/p>\n<h3>7. \u041f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a<\/h3>\n<p>\u0412 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435 \u043d\u0430\u0431\u0438\u0440\u0430\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<pre><code class=\"bash\">go run cmd\/main.go<\/code><\/pre>\n<p>\u0412 \u0430\u0434\u0440\u0435\u0441\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435: <a href=\"http:\/\/localhost:8080\/\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:2000\/<\/a><\/p>\n<p>\u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f GraphQL playground:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" height=\"1808\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/448\/aa4\/a35\/448aa4a35a8a67971d1d3f92235c1ae9.png\" data-width=\"2580\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c, \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e\u0439. <br \/>\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u0432 <a href=\"https:\/\/habr.com\/ru\/post\/599723\/\" rel=\"noopener noreferrer nofollow\">\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438<\/a><\/p>\n<\/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\/598359\/\"> https:\/\/habr.com\/ru\/post\/598359\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\" class=\"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>\u042d\u0442\u043e \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0435\u0435 \u0441\u0445\u0435\u043c\u0443 \u0440\u0430\u0431\u043e\u0442\u044b &#171;\u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0439&#187; \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u041f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u0430\u0432\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0432\u044b\u0434\u0430\u044e\u0442\u0441\u044f \u0441 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e.<\/p>\n<h2>\u0417\u0430\u0434\u0430\u0447\u0430<\/h2>\n<p>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c\u0441\u044f &#171;\u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c&#187; \u043e\u0431\u0440\u0430\u0437\u043e\u043c: \u043a\u043e\u0434 \u0432 \u0421\u041c\u0421 \u043b\u0438\u0431\u043e \u043a\u043e\u0434 \u0432 URL. \u041f\u0430\u0440\u043e\u043b\u044c \u0443 user \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442.<\/p>\n<h3>\u041a\u0435\u0439\u0441<\/h3>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432 \u0444\u043e\u0440\u043c\u0435 \u0432\u0445\u043e\u0434\u0430 \u0432\u0432\u043e\u0434\u0438\u0442 \u0441\u0432\u043e\u0439 Username, \u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043c\u0435\u0442\u043e\u0434\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442:<\/p>\n<ul>\n<li>\n<p>\u041f\u0438\u0441\u044c\u043c\u043e \u0441 <strong>\u043a\u043d\u043e\u043f\u043a\u043e\u0439<\/strong> \u043d\u0430 \u0435\u043c\u0430\u0439\u043b, \u043f\u0440\u0438 \u0435\u0435 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 \u2013 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f. \u041f\u043e\u0447\u0442\u043e\u0432\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0444\u043e\u0440\u043c\u0430 \u0432\u0432\u043e\u0434\u0430 \u043a\u043e\u0434\u0430 \u0438\u0437 \u0421\u041c\u0421, \u043f\u0440\u0438 \u0443\u0441\u043f\u0435\u0445\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u0442\u0441\u044f<\/p>\n<\/li>\n<\/ul>\n<h3>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430<\/h3>\n<p>\u041c\u044b \u043d\u0435 \u0437\u043d\u0430\u0435\u043c \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c <strong>\u043d\u0430\u0436\u043c\u0435\u0442 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443<\/strong>. \u041d\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0435\u0435 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043d\u044f\u0442\u044c \u0447\u0442\u043e \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c HTTP \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u043e\u043a\u0435\u043d. <\/p>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0441\u0435\u0441\u0441\u0438\u0438 \u043f\u043e \u043f\u0440\u0435\u0434\u044c\u044f\u0432\u043b\u0435\u043d\u0438\u044e \u2013 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 <code>ClientID<\/code>. <\/p>\n<h3>\u041a\u0430\u043a \u0440\u0435\u0448\u0430\u0442\u044c?<\/h3>\n<ol>\n<li>\n<p>\u041f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 <s>\u0431\u0440\u0430\u0443\u0437\u0435\u0440<\/s> <strong>\u041a\u043b\u0438\u0435\u043d\u0442<\/strong> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 cookie c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c <code>ClientID<\/code> <\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435 <strong>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c<\/strong> \u0444\u043e\u0440\u043c\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043a\u0435\u043d \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 <code>Auth_token<\/code> \u2013 \u043e\u0431\u043c\u0435\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0442\u043e\u043a\u0435\u043d <strong>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/strong><\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u0441\u0435\u0441\u0441\u0438\u044f, \u0445\u0440\u0430\u043d\u0438\u0442 <code>Auth_token<\/code> , <code>ClientID<\/code> \u0438 <code>UserID<\/code><\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c<\/strong> \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0435\u0442 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e. \u0418\u0449\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043f\u043e <code>ClientID<\/code> \u0432 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f\u0445 websocket \u2013 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u0438\u0433\u043d\u0430\u043b \u043e\u0431 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p><strong>\u041a\u043b\u0438\u0435\u043d\u0442<\/strong> \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0441\u0438\u0433\u043d\u0430\u043b \u043e \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f GET-\u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u0442\u043e\u043a\u0435\u043d\u043e\u043c <code>Auth_token<\/code> \u0432 HTTP-\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 Authorization. \u0418\u0449\u0435\u043c <code>Auth_token<\/code> \u0432 \u0441\u0435\u0441\u0441\u0438\u044f\u0445, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0445\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u043c <strong>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/strong><\/p>\n<\/li>\n<\/ol>\n<blockquote>\n<p>\u0421\u0442\u0430\u0442\u044c\u044f \u0440\u0430\u0437\u0431\u0438\u0442\u0430 \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0447\u0430\u0441\u0442\u0435\u0439:<br \/>&#8212; <a href=\"https:\/\/habr.com\/ru\/post\/599723\/\" rel=\"noopener noreferrer nofollow\">\u0447\u0430\u0441\u0442\u044c 2<\/a><br \/>&#8212; \u0447\u0430\u0441\u0442\u044c 3 &#8212; \u0432 \u0440\u0430\u0431\u043e\u0442\u0435<br \/>&#8212; <a href=\"https:\/\/github.com\/zhivulinal\/react-apollo-gqlgen-tutorial\/tree\/f34c72e0d9029f6d77966c3797810f38c6bf9f08\" rel=\"noopener noreferrer nofollow\">\u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438<\/a><\/p>\n<\/blockquote>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h3>\n<ol>\n<li>\n<p>\u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c <a href=\"https:\/\/gqlgen.com\/getting-started\/\" rel=\"noopener noreferrer nofollow\">Gqlgen<\/a><\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c <a href=\"https:\/\/graphql.org\/learn\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0445\u0435\u043c\u044b GraphQL<\/a>, \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0410\u041f\u0418<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c CORS<\/p>\n<\/li>\n<li>\n<p>GraphQL \u0441\u0435\u0440\u0432\u0435\u0440<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c websocket \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>Store<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a<\/p>\n<\/li>\n<\/ol>\n<h3>1. \u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c Gqlgen<\/h3>\n<p><a href=\"https:\/\/www.google.com\/search?q=Gqlgen+how+use&amp;rlz=1C5CHFA_enRU904RU904&amp;oq=Gqlgen+how+use&amp;aqs=chrome..69i57j0i333.7285j0j7&amp;sourceid=chrome&amp;ie=UTF-8\" rel=\"noopener noreferrer nofollow\">\u0421\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 Gqlgen<\/a> \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435 \u043c\u0430\u043b\u043e. \u041c\u044b \u0432\u044b\u0431\u0440\u0430\u043b\u0438 \u0442\u043e\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u043c \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u043c.<\/p>\n<h4>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:<\/h4>\n<ul>\n<li>\n<p><code>\/backoffice\/cmd<\/code>\u00a0\u2013 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b<\/p>\n<\/li>\n<li>\n<p><code>\/backoffice\/graph<\/code>\u00a0\u2013 \u0444\u0430\u0439\u043b\u044b GraphQL<\/p>\n<\/li>\n<li>\n<p><code>\/backoffice\/schema<\/code>\u00a0\u2013 GraphQL \u0441\u0445\u0435\u043c\u044b<\/p>\n<\/li>\n<li>\n<p><code>\/backoffice\/models<\/code>\u00a0\u2013 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 GraphQL<\/p>\n<\/li>\n<li>\n<p><code>\/backoffice\/pkg<\/code>\u00a0\u2013 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>backoffice<\/code>, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c:<\/p>\n<pre><code class=\"bash\">go mod init react-apollo-gqlgen-tutorial\/backoffice go get github.com\/99designs\/gqlgen go run github.com\/99designs\/gqlgen init<\/code><\/pre>\n<p>\u041e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b gqlgen.yml:<\/p>\n<pre><code class=\"yaml\"># \u0418\u0437\u043c\u0435\u043d\u0438\u043c \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0444\u0430\u0439\u043b\u043e\u0432 \u0441\u0445\u0435\u043c\u044b schema:   - schema\/*.graphqls  # \u0418\u0437\u043c\u0435\u043d\u0438\u043c \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 model:   filename: models\/models_gen.go   package: model    # \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 # \u0427\u0442\u043e\u0431\u044b \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043d\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u0442\u0438\u0440\u0430\u043b \u0443\u0436\u0435 \u0438\u043c\u0435\u044e\u0449\u0435\u0435\u0441\u044f autobind:   - \"react-apollo-gqlgen-tutorial\/backoffice\/models\"<\/code><\/pre>\n<p>\u041f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u0443\u0435\u043c \u0444\u0430\u0439\u043b <code>server.go<\/code> \u0432 <code>main.go<\/code> \u0438 \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u043c \u0435\u0433\u043e \u0432\u00a0<code>\/backoffice\/cmd<\/code>.<\/p>\n<p>\u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438\u00a0<code>\/backoffice\/cmd<\/code> \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <code>gqlgen.go<\/code>:<\/p>\n<blockquote>\n<p>\/\/ +build tools \u2013 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439, <a href=\"https:\/\/github.com\/golang\/go\/wiki\/Modules#how-can-i-track-tool-dependencies-for-a-module\" rel=\"noopener noreferrer nofollow\">\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0437\u0434\u0435\u0441\u044c<\/a><\/p>\n<\/blockquote>\n<pre><code class=\"go\">\/\/ +build tools  package main  import ( \"fmt\" \"github.com\/99designs\/gqlgen\/cmd\" )  func main() { fmt.Println(\"Building Graphql schema\") cmd.Execute() }<\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u0438 \u0438\u0437 \u0441\u0445\u0435\u043c\u044b GraphQL \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u044b:<\/p>\n<pre><code class=\"bash\">go run cmd\/gqlgen.go<\/code><\/pre>\n<h3>2. \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0441\u0445\u0435\u043c\u044b GraphQL, \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0410\u041f\u0418<\/h3>\n<p>\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c 3 \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0445: <code>Auth<\/code>, <code>Session<\/code>, <code>User<\/code> \u0438 \u043c\u0435\u0442\u043e\u0434\u044b GraphQL.<\/p>\n<p>Schema <code>schema\/schema.graphqls<\/code>:<\/p>\n<pre><code class=\"dart\">\"\"\" \u0417\u0430\u043f\u0440\u043e\u0441\u044b GET \"\"\" type Query {    \"\"\"   \u041f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438    \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0444\u043b\u0430\u0433\u0430 Auth.authorized      1. \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c Auth.auth_token \u0438 Auth.authorized   \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0435\u0433\u043e \u0432 HTTP \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 Authorization      2. \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c Auth.client_id   \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 Client-ID   \"\"\"   auth: Auth!    user: User! }  \"\"\" \u0417\u0430\u043f\u0440\u043e\u0441\u044b POST \"\"\" type Mutation {    \"\"\"   \u041c\u0435\u0442\u043e\u0434 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.   \u041f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 username   \u0412\u0435\u0440\u043d\u0435\u0442 Auth.auth_token, \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0432    HTTP \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 Authorization   \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f   \"\"\"   authorization(login: String!): Auth!   smsCode(code: String!): Auth! }  \"\"\" \u041f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 websocket \"\"\" type Subscription {    \"\"\"   \u041f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 \u043d\u0430 Auth   \"\"\"   auth: Auth! }<\/code><\/pre>\n<p>Session <code>schema\/session.graphqls<\/code>:<\/p>\n<pre><code class=\"dart\">type Session {      \"\"\"     \u0422\u043e\u043a\u0435\u043d \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0432\u043f\u0430\u0441\u0442\u044c \u0441 \u0442\u0435\u043c     \u0447\u0442\u043e \u043e\u0442\u0434\u0430\u043b\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u043f\u0440\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435 \u0444\u043e\u0440\u043c\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438     \"\"\"     auth_token: String!      \"\"\"     \u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     \"\"\"     uid:    Int!      \"\"\"     \u041c\u0435\u0442\u043e\u0434 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c     \"\"\"     method: String! }<\/code><\/pre>\n<p>Auth <code>schema\/auth.graphqls<\/code>:<\/p>\n<pre><code class=\"dart\">type Auth {      \"\"\"     \u0414\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u044a\u044f\u0432\u043b\u0435\u043d \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0442\u043e\u043a\u0435\u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u043d\u0430 GET \u0437\u0430\u043f\u0440\u043e\u0441 \u0444\u043e\u0440\u043c\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438      \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432 HTTP \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 Client-ID     \"\"\"     client_id:      String!      \"\"\"     \u0414\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u044a\u044f\u0432\u043b\u0435\u043d \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0442\u043e\u043a\u0435\u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u043d\u0430 GET \u0437\u0430\u043f\u0440\u043e\u0441 \u0444\u043e\u0440\u043c\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438      \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432 HTTP \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 Authorization     \"\"\"     token:      String!      \"\"\"     \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438     \"\"\"     authorized: Boolean!      \"\"\"     \u041c\u0435\u0442\u043e\u0434 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438     \"\"\"     method: String! }<\/code><\/pre>\n<p>\u041d\u0430 <code>User<\/code> \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/github.com\/zhivulinal\/react-apollo-gqlgen-tutorial\/blob\/6acbcfe4c9454aaa735ef0a1264820ae1af5cdf3\/backoffice\/schema\/user.graphqls\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a><\/p>\n<h3>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u0432<\/h3>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 \u0441\u0445\u0435\u043c GraphQL \u0431\u044b\u043b\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<pre><code class=\"bash\">go run cmd\/gqlgen.go<\/code><\/pre>\n<p>\u042d\u0442\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0441\u043e\u0437\u0434\u0430\u0441\u0442 <code>\/backoffice\/models<\/code>  \u043d\u043e \u043d\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>\/backoffice\/graph<\/code>. <\/p>\n<h4>backoffice\/graph:<\/h4>\n<ol>\n<li>\n<p>\u0423\u0434\u0430\u043b\u044f\u0435\u043c \u043f\u0430\u043f\u043a\u0443 models \u0432 <code>\/backoffice\/graph<\/code><\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0435\u043c \u0444\u0430\u0439\u043b\u044b: <code>resolver.go<\/code> \u0438 <code>schema.resolvers.go<\/code> \u0432  <code>\/backoffice\/pkg\/graph<\/code><\/p>\n<\/li>\n<\/ol>\n<h4>backoffice\/pkg\/qraph:<\/h4>\n<p>\u041e\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b <code>schema.resolvers.go<\/code> \u0437\u0430\u0431\u0435\u0440\u0435\u043c \u043c\u0435\u0442\u043e\u0434\u044b \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0438\u0435\u0441\u044f \u043a <code>*model.Auth<\/code> \u0438 <code>*model.User<\/code> . \u041f\u043e\u043c\u0435\u0441\u0442\u0438\u043c \u0438\u0445 \u0432 <code>auth.go<\/code> \u0438 <code>user.go<\/code> \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430<\/p>\n<p>\u0417\u0430\u0442\u044f\u043d\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<pre><code>go mod vendor<\/code><\/pre>\n<h4>\u041f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0430\u044f\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:<\/h4>\n<p><a href=\"https:\/\/github.com\/zhivulinal\/react-apollo-gqlgen-tutorial\/tree\/278f43d7d75f7c4d68e7c9572ef134d923e529b9\" rel=\"noopener noreferrer nofollow\">\u041a\u043e\u043c\u043c\u0438\u0442 Github<\/a><\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<h3>3. \u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c CORS<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u0437\u0430\u0449\u0438\u0442\u0443 \u043e\u0442 CSRF \u0430\u0442\u0430\u043a<\/p>\n<pre><code class=\"go\">func CorsMiddleware() func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {  \/\/ \u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 \u0445\u043e\u0441\u0442\u0443       \/\/ \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e \u0432\u0441\u0435\u0433\u0434\u0430 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0430\u0434\u0440\u0435\u0441 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0445\u043e\u0441\u0442\u0430       \/\/ \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u044f \u0437\u0432\u0435\u0437\u0434\u043e\u0447\u043a\u0443 \"*\" - \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 w.Header().Set(\"Access-Control-Allow-Origin\", \"http:\/\/localhost:3000\")  \/\/ \u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u043c \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b cookie \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442 http:\/\/localhost:3000 \/\/ \/\/ \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u044f \/\/ Access-Control-Allow-Origin \u0438 Access-Control-Allow-Credentials \/\/ \u0412 \u044d\u0442\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u0435: \/\/ https:\/\/fetch.spec.whatwg.org\/#cors-protocol-and-credentials w.Header().Set(\"Access-Control-Allow-Credentials\", \"true\")  \/\/ \u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u044b w.Header().Set(\"Access-Control-Allow-Methods\", \"POST, GET, OPTIONS, PUT, DELETE\")  \/\/ \u0411\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c CSRF \/\/ Access-Control-Allow-Headers = Content-Type \/\/ \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0437\u0434\u0435\u0441\u044c: \/\/ https:\/\/fetch.spec.whatwg.org\/#concept-header w.Header().Set(\"Access-Control-Allow-Headers\", \"Accept, Content-Type, Content-Length, Accept-Encoding, Authorization\")  if r.Method == \"OPTIONS\" { return }  next.ServeHTTP(w, r) }) } }<\/code><\/pre>\n<blockquote>\n<p>\u0414\u043b\u044f \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u043e\u0439 \u0437\u0430\u0449\u0438\u0442\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0440\u0430\u043d\u0438\u0442\u044c XSS-\u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0438. <br \/><a href=\"https:\/\/academind.com\/tutorials\/localstorage-vs-cookies-xss\" rel=\"noopener noreferrer nofollow\">\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0430 \u044d\u0442\u0443 \u0442\u0435\u043c\u0443<\/a> \u0430\u043d\u0433\u043b.<\/p>\n<\/blockquote>\n<h3>4. GraphQL \u0441\u0435\u0440\u0432\u0435\u0440<\/h3>\n<p>\u041c\u044b \u0443\u0436\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u043b\u0438 \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0444\u0430\u0439\u043b\u044b \u0432 <code>\/pkg\/qraph<\/code>. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c <code>resolver.go<\/code>:<\/p>\n<pre><code class=\"go\">var ( mb int64 = 1 &lt;&lt; 20 )  type Resolver struct{}  \/\/ \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e NewServer func NewServer(opt Options) *handler.Server {  \/\/ \u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438\u0437 cmd\/main.go srv := handler.New( generated.NewExecutableSchema( generated.Config{ Resolvers: &amp;Resolver{}, }, ), ) srv.AddTransport(transport.MultipartForm{ MaxMemory:     32 * mb, MaxUploadSize: 50 * mb, }) srv.AddTransport(transport.POST{}) srv.AddTransport(transport.GET{}) srv.AddTransport(transport.Websocket{ KeepAlivePingInterval: 10 * time.Second, Upgrader: websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, ReadBufferSize:  1024, WriteBufferSize: 1024, }, InitFunc: transport.WebsocketInitFunc(func(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) { return ctx, nil }), }) srv.Use(extension.Introspection{})  return srv }  type Options struct {}<\/code><\/pre>\n<h3>5. Websocket \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 <\/h3>\n<p>\u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 websocket \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/github.com\/gorilla\/websocket\" rel=\"noopener noreferrer nofollow\">Gorilla websocket<\/a> \u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 HTTP \u2013 <a href=\"https:\/\/github.com\/gorilla\/mux\" rel=\"noopener noreferrer nofollow\">Gorilla mux<\/a><\/p>\n<p>\u0418\u0437\u043c\u0435\u043d\u0438\u043c <code>cmd\/main.go<\/code>:<\/p>\n<pre><code class=\"go\">import (   \/\/...    \"react-apollo-gqlgen-tutorial\/backoffice\/pkg\/graph\" \"github.com\/gorilla\/mux\" )  var ( defaultPort = \"2000\" )  func main() { port := os.Getenv(\"PORT\") if port == \"\" { port = defaultPort }    \/\/ \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c GraphQL \u0441\u0435\u0440\u0432\u0435\u0440 srv := graph.NewServer(graph.Options{})  \/\/ \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0440\u043e\u0443\u0442\u0435\u0440 router := mux.NewRouter()  \/\/ \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c CORS middleware router.Use(middleware.CorsMiddleware())  router.Handle(\"\/\", playground.Handler(\"GraphQL playground\", \"\/graphql\")) router.Handle(\"\/graphql\", srv)  log.Printf(\"connect to http:\/\/localhost:%s\/ for GraphQL playground\", port) log.Fatal(http.ListenAndServe(\":\"+port, router)) }<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/zhivulinal\/react-apollo-gqlgen-tutorial\/tree\/4c1e24ce089f14b2831b241b4349a9ed19517154\" rel=\"noopener noreferrer nofollow\">\u041a\u043e\u043c\u043c\u0438\u0442 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u044d\u0442\u0430\u043f\u0430<\/a><\/p>\n<h3>6. Store <\/h3>\n<p>\u0412 \u043d\u0430\u0448\u0435\u0439 \u043b\u043e\u0433\u0438\u043a\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439:<\/p>\n<ol>\n<li>\n<p><code>Session<\/code>: \u0445\u0440\u0430\u043d\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0431 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0439 \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0441\u0435\u0441\u0441\u0438\u044f\u0445, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c<\/p>\n<\/li>\n<li>\n<p><code>Auth<\/code>: \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/p>\n<\/li>\n<li>\n<p><code>User<\/code>: \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c<\/p>\n<\/li>\n<\/ol>\n<p>Store \u043f\u043e \u0444\u0430\u043a\u0442\u0443 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u043e\u043c, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u043c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0449\u0438\u0435 \u043e\u0431\u0449\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443. <\/p>\n<p>\u041e\u043f\u0438\u0448\u0435\u043c Store <code>\/backoffice\/pkg\/store<\/code>:<\/p>\n<pre><code class=\"go\">package store  type Store struct { token TokenOptions }  func NewStore(opt Options) *Store { return &amp;Store{ token: opt.Token, } }  type Options struct { Token TokenOptions }  type TokenOptions struct {}<\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0435\u0442\u043e\u0434\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0430 GraphQL.<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b <code>Auth<\/code>:<\/p>\n<pre><code class=\"go\">\/\/ pkg\/store\/auth.go  \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 Auth \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 func (s *Store) Auth(ctx context.Context) (auth *model.Auth, err error) { \/\/ ... return }  \/\/ \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u0442 websocket, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043a\u0430\u043d\u0430\u043b func (s *Store) AuthCreateWebsocket(ctx context.Context) (out &lt;-chan *model.Auth, err error) { \/\/ ... return }  \/\/ \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043e Username func (s *Store) AuthorizeForUsername(ctx context.Context, login string) (auth *model.Auth, err error) { \/\/ ... return }  \/\/ \u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0437 \u0421\u041c\u0421 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f func (s *Store) AuthSMSApprove(ctx context.Context, code string) (auth *model.Auth, err error) { \/\/ ... return }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b <code>User<\/code>:<\/p>\n<pre><code class=\"go\">\/\/ pkg\/store\/user.go  \/\/ \u0412\u0435\u0440\u043d\u0435\u0442 User \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 func (s *Store) User(ctx context.Context) (user *model.User, err error) { \/\/ ... return }<\/code><\/pre>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c <code>Store<\/code> \u0432 <code>pkg\/graph\/resolver.go<\/code>:<\/p>\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-327257","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/327257","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=327257"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/327257\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=327257"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=327257"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=327257"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}