{"id":408867,"date":"2024-06-29T20:25:54","date_gmt":"2024-06-29T20:25:54","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=408867"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=408867","title":{"rendered":"<span>GraphQL \u0432 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0438\u0448\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f iOS<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/x3\/za\/hx\/x3zahxlnt9x9jjlzewyixoyphck.png\" data-src=\"https:\/\/habrastorage.org\/webt\/x3\/za\/hx\/x3zahxlnt9x9jjlzewyixoyphck.png\"\/><\/p>\n<p>  <i>\u0414\u043e\u0431\u0440\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0443\u0442\u043e\u043a! \u0421 \u0432\u0430\u043c\u0438 \u0410\u043d\u043d\u0430 \u0416\u0430\u0440\u043a\u043e\u0432\u0430, \u0432\u0435\u0434\u0443\u0449\u0438\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438\u00a0Usetech, \u0438 \u043c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u043d\u0430\u0448\u0443 \u0441\u0435\u0440\u0438\u044e \u0441\u0442\u0430\u0442\u0435\u0439, \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u044b\u0445 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0435\u0439\u00a0GraphQL\u00a0\u00a0\u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. <\/i><\/p>\n<p>  \u0412 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0447\u0430\u0441\u0442\u044f\u0445 \u043c\u044b \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/usetech\/blog\/645273\/\">\u043e \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0435 \u043e\u0431\u043b\u0430\u0447\u043d\u043e\u0433\u043e\u00a0GraphQL\u00a0\u0431\u0435\u043a\u0435\u043d\u0434\u0430 \u043d\u0430\u00a0Hasura<\/a>\u00a0\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/usetech\/blog\/645789\/\">\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438\u00a0GraphQL\u00a0API\u00a0\u043a\u00a0Android\u00a0\u043a\u043b\u0438\u0435\u043d\u0442\u0443<\/a>. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0441\u0442\u0430\u043b \u0447\u0435\u0440\u0435\u0434\u00a0iOS\u00a0\u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. <\/p>\n<p>  \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u00a0Apollo\u00a0GraphQL\u00a0\u0434\u043b\u044f\u00a0iOS:<\/p>\n<p>  <a href=\"https:\/\/www.apollographql.com\/docs\/ios\/\">www.apollographql.com\/docs\/ios<\/a><\/p>\n<p>  <a href=\"https:\/\/github.com\/apollographql\/apollo-ios\">github.com\/apollographql\/apollo-ios<\/a><\/p>\n<p>  \u041d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e\u0435\u00a0Android\u00a0\u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u0442\u0430\u043a\u0438\u0435 \u0436\u0435 \u043f\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0443 \u044d\u043a\u0440\u0430\u043d\u044b:<\/p>\n<p>   \u2014 \u0432\u0445\u043e\u0434<\/p>\n<p>   \u2014 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f<\/p>\n<p>   \u2014 \u043b\u0435\u043d\u0442\u0430 \u043f\u043e\u0441\u0442\u043e\u0432<\/p>\n<p>   \u2014 \u044d\u043a\u0440\u0430\u043d \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u0430<\/p>\n<p>   \u2014 \u044d\u043a\u0440\u0430\u043d \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435.<\/p>\n<p>  <a name=\"habracut\"><\/a><br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/er\/yo\/fn\/eryofnqsaswewjyqa3wrzg0bgls.png\" width=\"30%\" data-src=\"https:\/\/habrastorage.org\/webt\/er\/yo\/fn\/eryofnqsaswewjyqa3wrzg0bgls.png\"\/><\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/om\/ny\/jh\/omnyjhtkfxsvyu91vdlw1vjq8zu.png\" width=\"30%\" data-src=\"https:\/\/habrastorage.org\/webt\/om\/ny\/jh\/omnyjhtkfxsvyu91vdlw1vjq8zu.png\"\/><\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/dv\/vw\/df\/dvvwdfosff1_qan_ye7z0svu4z8.png\" width=\"30%\" data-src=\"https:\/\/habrastorage.org\/webt\/dv\/vw\/df\/dvvwdfosff1_qan_ye7z0svu4z8.png\"\/><\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/nb\/ej\/ux\/nbejux6o85-xuyuo-dpjajjzei8.png\" width=\"30%\" data-src=\"https:\/\/habrastorage.org\/webt\/nb\/ej\/ux\/nbejux6o85-xuyuo-dpjajjzei8.png\"\/><\/p>\n<p>  \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 Apollo GraphQL. \u0414\u0430\u043d\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 SPM \u0441 github <a href=\"https:\/\/github.com\/apollographql\/apollo-ios\">github.com\/apollographql\/apollo-ios<\/a><\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/hz\/oq\/lc\/hzoqlcygkfgky_mkvpuvrceliy4.png\" width=\"80%\" data-src=\"https:\/\/habrastorage.org\/webt\/hz\/oq\/lc\/hzoqlcygkfgky_mkvpuvrceliy4.png\"\/><\/p>\n<p>  \u0414\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0431\u0440\u0430\u0442\u044c Apollo \u0438 ApolloWebSocket \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/m6\/cu\/gd\/m6cugdk5usdyk5k1v01xampzazu.png\" width=\"80%\" data-src=\"https:\/\/habrastorage.org\/webt\/m6\/cu\/gd\/m6cugdk5usdyk5k1v01xampzazu.png\"\/><\/p>\n<p>  \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u043f\u0430\u043a\u0435\u0442\u043e\u0432 0.49.1:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/n9\/yt\/xn\/n9ytxnepyhs0ayhdhkvgxgylgry.png\" data-src=\"https:\/\/habrastorage.org\/webt\/n9\/yt\/xn\/n9ytxnepyhs0ayhdhkvgxgylgry.png\"\/><\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0432\u044b\u043a\u0430\u0447\u0430\u0442\u044c \u0441\u0445\u0435\u043c\u0443. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u043c \u0447\u0435\u0440\u0435\u0437 npm apollo-codegen:   <\/p>\n<pre><code class=\"swift\">npm i apollo-codegen<\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443, \u0443\u043a\u0430\u0437\u0430\u0432 \u043f\u0443\u0442\u044c \u043a API, \u043f\u0443\u0442\u044c \u0434\u043b\u044f \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438:<\/p>\n<pre><code class=\"swift\">apollo-codegen download-schema \"&lt;host>.hasura.app\/v1\/graphql\"  --output schema.json --header \"x-hasura-admin-secret: &lt;key>\" <\/code><\/pre>\n<p>  \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 schema.json \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0430 \u0432\u0435\u0440\u0445\u043d\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430: <br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/pm\/yl\/hq\/pmylhqdinlfly_irkptiaowxdnw.png\" data-src=\"https:\/\/habrastorage.org\/webt\/pm\/yl\/hq\/pmylhqdinlfly_irkptiaowxdnw.png\"\/><\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e. \u0418\u0434\u0435\u043c \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0443 Build Phase \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 New Run Script Phase:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/vs\/mo\/fn\/vsmofnxar62qv7-or7dsaj0dbxc.png\" data-src=\"https:\/\/habrastorage.org\/webt\/vs\/mo\/fn\/vsmofnxar62qv7-or7dsaj0dbxc.png\"\/><\/p>\n<p>  \u041d\u0430\u0437\u043e\u0432\u0435\u043c \u044d\u0442\u0443 \u0444\u0430\u0437\u0443, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, CLI \u0438 \u043f\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u043c \u043d\u0430 2\u044e \u0441\u0442\u0440\u043e\u043a\u0443, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0430 \u0448\u043b\u0430 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439.<\/p>\n<p>  \u0417\u0430\u043c\u0435\u043d\u0438\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u0443\u044e \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0443 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u043e\u043c:  <\/p>\n<pre><code class=\"bash\"># Go to the build root and search up the chain to find the Derived Data Path where the source packages are checked out. DERIVED_DATA_CANDIDATE=\"${BUILD_ROOT}\"  while ! [ -d \"${DERIVED_DATA_CANDIDATE}\/SourcePackages\" ]; do   if [ \"${DERIVED_DATA_CANDIDATE}\" = \/ ]; then     echo >&amp;2 \"error: Unable to locate SourcePackages directory from BUILD_ROOT: '${BUILD_ROOT}'\"     exit 1   fi    DERIVED_DATA_CANDIDATE=\"$(dirname \"${DERIVED_DATA_CANDIDATE}\")\" done  # Grab a reference to the directory where scripts are checked out SCRIPT_PATH=\"${DERIVED_DATA_CANDIDATE}\/SourcePackages\/checkouts\/apollo-ios\/scripts\"  if [ -z \"${SCRIPT_PATH}\" ]; then     echo >&amp;2 \"error: Couldn't find the CLI script in your checked out SPM packages; make sure to add the framework to your project.\"     exit 1 fi  cd \"${SRCROOT}\/${TARGET_NAME}\" \"${SCRIPT_PATH}\"\/run-bundled-codegen.sh codegen:generate  --target=swift --includes=.\/**\/*.graphql --localSchemaFile=\"schema.json\" API.swift<\/code><\/pre>\n<p>  \u0412 \u0441\u043a\u0440\u0438\u043f\u0442\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043f\u0443\u0442\u044c \u043a \u0441\u0445\u0435\u043c\u0435 \u0438 \u0444\u0430\u0439\u043b\u0443 API, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0435\u0435 \u043e\u0441\u043d\u043e\u0432\u0435.<\/p>\n<p>  \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u0431\u0438\u043b\u0434\u0438\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442. \u041f\u0435\u0440\u0432\u0430\u044f \u0441\u0431\u043e\u0440\u043a\u0430 \u0432\u044b\u0434\u0430\u0441\u0442 \u043d\u0430\u043c \u043e\u0448\u0438\u0431\u043a\u0443 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438. \u042d\u0442\u043e \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043c\u044b \u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 graphql \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043d\u0430\u0448\u0435\u0433\u043e API.<\/p>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0430\u0439\u043b \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c .graphql \u043d\u0430 \u0442\u043e\u0442 \u0436\u0435 \u0443\u0440\u043e\u0432\u0435\u043d\u044c, \u0433\u0434\u0435 \u0443 \u043d\u0430\u0441 \u043b\u0435\u0436\u0438\u0442 \u0441\u0445\u0435\u043c\u0430. \u041f\u043e\u0441\u043b\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0444\u0430\u0439\u043b API.swift, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043d\u0430 \u0442\u043e\u0442 \u0436\u0435 \u0443\u0440\u043e\u0432\u0435\u043d\u044c, \u0433\u0434\u0435 \u0443 \u043d\u0430\u0441 \u043b\u0435\u0436\u0430\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b.<\/p>\n<p>  \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u043e\u0434 \u043d\u0430\u0448\u0438\u0445 query \u0438 mutation:<\/p>\n<pre><code class=\"swift\">query PostsQuery {     posts {             post_id, post_text, user_id, user_name, likes, date, image_link     } }  mutation AddPostMutation($postId: uuid, $text: String, $image: String, $user: String, $userId: uuid, $date: date) {     insert_posts_one(object: {date: $date, image_link: $image, post_id: $postId, post_text: $text, user_id: $userId, user_name: $user}) {        ... Post     } }  mutation DeletePost($postId: uuid!) {     delete_posts_by_pk(post_id: $postId){         post_id     }     delete_comments(where: {post_id: {_eq: $postId}}) {         returning {             comment_id         }     } }  query Users {     users {        user_email, user_id, user_name     } }  query GetPostQuery($postId: uuid) {     posts(where: {post_id: {_eq: $postId}}) {            post_id, post_text, user_id, user_name, likes, date, image_link     }     likes(where: {post_id: {_eq: $postId}}){             post_id, user_id     }     comments(where: {post_id: {_eq: $postId}}){             comment_id, comment_text, user_id, post_id, user_name     } }  mutation CreateUserMutation($name: String, $id: uuid, $email: String, $password: String) {     insert_users_one(object: {user_email: $email, user_id: $id, user_name: $name, password: $password}) {         ... User     } }  query GetUser($email: String, $password: String) {     users(where: {password: {_eq: $password}, user_email: {_eq: $email}}) {            user_email, user_id, user_name     } }  query Likes($postId: uuid) {     likes(where: {post_id: {_eq: $postId}}){            post_id, user_id     } }  query Comments($commentId: uuid) {     comments(where: {post_id: {_eq: $commentId}}) {             comment_id, comment_text, user_id, post_id, user_name     } }  mutation  ChangeLikeMutation($postId: uuid, $likes: String) {     update_posts(where: {post_id: {_eq: $postId}} _set: {likes: $likes}) {         __typename     } }  mutation  ChangePostMutation($postId: uuid!, $postText: String, $imageLink: String) {     update_posts(where: {post_id: {_eq: $postId}} _set: {post_text: $postText, image_link: $imageLink}) {         __typename     } }  mutation CreateComment($postId: uuid, $commentText: String, $id: uuid, $userId: uuid, $userName: String) {     insert_comments_one(object: {post_id: $postId, comment_text: $commentText, comment_id: $id, user_id: $userId, user_name: $userName }) {         ... Comment     } }   fragment User on users {     user_email, user_id, user_name, likes }  fragment Comment on comments {     comment_id, comment_text, user_id, post_id, user_name }  fragment Post on posts {     post_id, post_text, user_id, user_name, likes, date, image_link }  fragment LikeForPost on likes {     post_id, user_id }<\/code><\/pre>\n<p>  \u0412 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435 \u043d\u0430\u0448\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b \u0442\u0435\u043c, \u0447\u0442\u043e \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0434\u043b\u044f Android \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0417\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0434\u043b\u044f Query \u043c\u044b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b. \u0422\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f Mutation.<br \/>  \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 query \u0441 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043e\u043c \u0432 \u043e\u0442\u0432\u0435\u0442\u0435:  <\/p>\n<pre><code class=\"swift\">query GetUserFr($email: String, $password: String) {     users(where: {password: {_eq: $password}, user_email: {_eq: $email}}) {                    ... User     } }<\/code><\/pre>\n<p>  \u041d\u043e \u043f\u0440\u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0442\u0430\u043a\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043e\u0448\u0438\u0431\u043a\u0443:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/yj\/27\/gq\/yj27gqa9eyoe0goj2dq0raiqsm4.png\" data-src=\"https:\/\/habrastorage.org\/webt\/yj\/27\/gq\/yj27gqa9eyoe0goj2dq0raiqsm4.png\"\/><\/p>\n<p>  \u0422\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0432 android \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0443 \u043a\u0430\u0436\u0434\u043e\u0433\u043e Query \u0438 Mutation \u0441\u0432\u043e\u0439 \u0442\u0438\u043f \u0438\u0437 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432. \u0422\u0438\u043f, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0434\u043b\u044f \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f Mutation. \u0424\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u043e\u043f\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043d\u0435 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u043c \u0442\u0438\u043f\u043e\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 Mutation, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0432 graphql, \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u0447\u0438\u0442\u0430\u0442\u044c\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0438 \u0442\u0435\u043c \u0436\u0435 \u0442\u0438\u043f\u043e\u043c.<\/p>\n<p>  \u042d\u0442\u043e \u0430\u0432\u0442\u043e\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u043a\u043e\u0434, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u0448\u0438 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0434\u0435\u0441\u044c \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u044b. <br \/>  \u0411\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u043a\u043e\u0434\u0435 Query \u044f\u0432\u043d\u043e\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435 \u043d\u0443\u0436\u043d\u044b\u0445 \u043d\u0430\u043c \u043f\u043e\u043b\u0435\u0439:<\/p>\n<pre><code class=\"swift\">query GetUser($email: String, $password: String) {     users(where: {password: {_eq: $password}, user_email: {_eq: $email}}) {            user_email, user_id, user_name     } } <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f.<\/p>\n<p>  \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 Android \u0432\u0441\u0435 \u043d\u0430\u0448\u0438 \u0442\u0438\u043f\u044b \u0438 \u043f\u043e\u043b\u044f \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 GraphQL \u0441 \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u043e\u043c \u0437\u0430\u043f\u0438\u0448\u0443\u0442\u0441\u044f \u0432 \u043e\u0434\u0438\u043d \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b:  <\/p>\n<pre><code class=\"swift\"> \/\/ \u041f\u0440\u0438\u043c\u0435\u0440\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 API.swift  import Apollo import Foundation  public final class PostsQueryQuery: GraphQLQuery {   \/\/\/ The raw GraphQL definition of this operation.   public let operationDefinition: String =     \"\"\"     query PostsQuery {       posts {         __typename         post_id         post_text         user_id         user_name         likes         date         image_link       }     }     \"\"\"    public let operationName: String = \"PostsQuery\"    public init() {   }    public struct Data: GraphQLSelectionSet {     public static let possibleTypes: [String] = [\"query_root\"]      public static var selections: [GraphQLSelection] {       return [         GraphQLField(\"posts\", type: .nonNull(.list(.nonNull(.object(Post.selections))))),       ]     }      public private(set) var resultMap: ResultMap      public init(unsafeResultMap: ResultMap) {       self.resultMap = unsafeResultMap     }      public init(posts: [Post]) {       self.init(unsafeResultMap: [\"__typename\": \"query_root\", \"posts\": posts.map { (value: Post) -> ResultMap in value.resultMap }])     }      \/\/\/ fetch data from the table: \"posts\"     public var posts: [Post] {       get {         return (resultMap[\"posts\"] as! [ResultMap]).map { (value: ResultMap) -> Post in Post(unsafeResultMap: value) }       }       set {         resultMap.updateValue(newValue.map { (value: Post) -> ResultMap in value.resultMap }, forKey: \"posts\")       }     }      public struct Post: GraphQLSelectionSet {       public static let possibleTypes: [String] = [\"posts\"]        public static var selections: [GraphQLSelection] {         return [           GraphQLField(\"__typename\", type: .nonNull(.scalar(String.self))),           GraphQLField(\"post_id\", type: .nonNull(.scalar(String.self))),           GraphQLField(\"post_text\", type: .scalar(String.self)),           GraphQLField(\"user_id\", type: .scalar(String.self)),           GraphQLField(\"user_name\", type: .scalar(String.self)),           GraphQLField(\"likes\", type: .scalar(String.self)),           GraphQLField(\"date\", type: .scalar(String.self)),           GraphQLField(\"image_link\", type: .scalar(String.self)),         ]       }        public private(set) var resultMap: ResultMap        public init(unsafeResultMap: ResultMap) {         self.resultMap = unsafeResultMap       }        public init(postId: String, postText: String? = nil, userId: String? = nil, userName: String? = nil, likes: String? = nil, date: String? = nil, imageLink: String? = nil) {         self.init(unsafeResultMap: [\"__typename\": \"posts\", \"post_id\": postId, \"post_text\": postText, \"user_id\": userId, \"user_name\": userName, \"likes\": likes, \"date\": date, \"image_link\": imageLink])       }<\/code><\/pre>\n<p>  \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u043f\u0440\u0438 \u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0438 Query \u0438 Mutation \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u043e\u0441\u0442\u0444\u0438\u043a\u0441\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438. <\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u043e\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0432 \u043d\u0430\u0448\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u0442\u0438\u043f\u043e\u0432 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u044b, \u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0442\u0438\u043f\u043e\u0432 Query. \u0414\u043b\u044f \u0432\u0441\u0435\u0445 Mutation, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442, \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u0442\u0438\u043f.<\/p>\n<pre><code class=\"swift\">struct PostItem : Codable, Equatable  { \/\/. . .     init(data: Post) {         self.uuid = data.postId         self.postText = data.postText ?? \"\"         self.id = data.postId         self.imageLink = data.imageLink ?? \"\"         self.userId = data.userId ?? \"\"         self.userName = data.userName ?? \"\"         self.likeItems = data.likes?.split(separator: \",\").map{LikeItem(userId: String($0), postId: data.postId)} ?? [LikeItem]()         self.dateString = data.date     }          init(data: PostsQueryQuery.Data.Post) {         self.postText = data.postText ?? \"\"         self.id = data.postId         self.uuid = data.postId         self.imageLink = data.imageLink ?? \"\"         self.userId = data.userId ?? \"\"         self.userName = data.userName ?? \"\"         self.likeItems = data.likes?.split(separator: \",\").map{LikeItem(userId: String($0), postId: data.postId)} ?? [LikeItem]()         self.dateString = data.date     }          init(data: GetPostQueryQuery.Data.Post) {         self.postText = data.postText ?? \"\"         self.id = data.postId         self.uuid = data.postId         self.imageLink = data.imageLink ?? \"\"         self.userId = data.userId ?? \"\"         self.userName = data.userName ?? \"\"         self.likeItems = data.likes?.split(separator: \",\").map{LikeItem(userId: String($0), postId: data.postId)} ?? [LikeItem]()         self.dateString = data.date     } }  struct UserData : Codable {   \/\/. . .      init(user: User) {         self.uid = user.userId         self.name = user.userName         self.email = user.userEmail     }          init(user: GetUserQuery.Data.User) {         self.uid = user.userId         self.name = user.userName         self.email = user.userEmail     } }      struct CommentItem : Codable { \/\/. . .         init(comment: Comment) {         self.userId = comment.userId         self.postId = comment.postId         self.userName = comment.userName ?? \"\"         self.text = comment.commentText         self.uuid = comment.commentId     }          init(comment: CommentsQuery.Data.Comment) {          self.userId = comment.userId          self.postId = comment.postId          self.userName = comment.userName ?? \"\"          self.text = comment.commentText          self.uuid = comment.commentId      }      }<\/code><\/pre>\n<p>  \u041c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u044c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u0430 \u0434\u043b\u044f \u043d\u0430\u0448\u0438\u0445 \u0442\u0438\u043f\u043e\u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<pre><code class=\"swift\">class QueryAdapter {     static let shared = QueryAdapter()     func loginUserQuery(email: String, password: String)-> GetUserQuery {         return GetUserQuery(email: email, password: password)     }          func loginUserQuery(userData: UserData)-> GetUserQuery {         return GetUserQuery(email: userData.email, password: userData.password)     }          func createUser(userData: UserData)->CreateUserMutationMutation {         return CreateUserMutationMutation(name: userData.name,id: UUID().uuidString, email: userData.email, password: userData.password)     }               func createPost(postItem: PostItem)->AddPostMutationMutation {         return AddPostMutationMutation(             postId: UUID().uuidString,             text: postItem.postText,             image: postItem.imageLink , user: postItem.userName,             userId: postItem.userId,             date: \"\\(Date())\")     }          func changeLike(postItem: PostItem)->ChangeLikeMutationMutation {         let likes = postItem.likeItems.map{$0.userId}.joined(separator: \",\")         return  ChangeLikeMutationMutation(postId: postItem.uuid, likes: likes)     }          func changePost(postItem: PostItem)->ChangePostMutationMutation {         return ChangePostMutationMutation(postId: postItem.uuid, postText: postItem.postText,imageLink: postItem.imageLink)     }     func deletePost(postItem: PostItem)-> DeletePostMutation {         return DeletePostMutation(postId: postItem.uuid)     }          func deletePostBy(postId: String)-> DeletePostMutation {         return DeletePostMutation(postId: postId)     }          func createComment(commentItem: CommentItem)->CreateCommentMutation {         return CreateCommentMutation(postId: commentItem.postId, commentText: commentItem.text, id: UUID().uuidString, userId: commentItem.userId,userName: commentItem.userName)     } } <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u043e\u0432 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u0430:<\/p>\n<pre><code class=\"swift\">extension PostItem {     func createPost()->AddPostMutationMutation {         return QueryAdapter.shared.createPost(postItem: self)     }          func changeLike()->ChangeLikeMutationMutation {         return QueryAdapter.shared.changeLike(postItem: self)     }          func changePost()->ChangePostMutationMutation {         return QueryAdapter.shared.changePost(postItem: self)     }     func deletePost()-> DeletePostMutation {         return QueryAdapter.shared.deletePost(postItem: self)     }          func deletePostById()-> DeletePostMutation {         return QueryAdapter.shared.deletePostBy(postId: self.uuid ?? \"\")     } }   extension UserData {     func createUser(userData: UserData)->CreateUserMutationMutation {         return QueryAdapter.shared.createUser(userData: self)     } }  extension CommentItem {     func createComment()->CreateCommentMutation {         return QueryAdapter.shared.createComment(commentItem: self)     } } <\/code><\/pre>\n<p>  \u041a\u0430\u0436\u0435\u0442\u0441\u044f, \u043c\u044b \u043a\u043e\u0435-\u0447\u0442\u043e \u0437\u0430\u0431\u044b\u043b\u0438. \u0410 \u0438\u043c\u0435\u043d\u043d\u043e \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<br \/>  \u0421\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438, \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0439 \u043a API \u0431\u0435\u0437 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043d\u0430\u043c \u0431\u044b\u043b\u043e \u0431\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a\u043e\u0433\u043e \u043a\u043e\u0434\u0430:  <\/p>\n<pre><code class=\"swift\">import Foundation import Apollo  class Network {   static let shared = Network()         private(set) lazy var apollo = ApolloClient(url: URL(string: \"http:\/\/host\/graphql\")!) } <\/code><\/pre>\n<p>  \u041d\u043e \u0443 \u043d\u0430\u0441 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0441 \u043a\u043b\u044e\u0447\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0434\u043b\u044f Hasura. <\/p>\n<p>  \u0414\u043b\u044f \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u043c\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430\u0448 \u043a\u043b\u0438\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u0432\u0438\u0434:  <\/p>\n<pre><code class=\"swift\">struct NetworkInterceptorProvider: InterceptorProvider {          \/\/ These properties will remain the same throughout the life of the `InterceptorProvider`, even though they     \/\/ will be handed to different interceptors.     private let store: ApolloStore     private let client: URLSessionClient          init(store: ApolloStore,          client: URLSessionClient) {         self.store = store         self.client = client     }          func interceptors&lt;Operation: GraphQLOperation>(for operation: Operation) -> [ApolloInterceptor] {         return [             MaxRetryInterceptor(),             CacheReadInterceptor(store: self.store),             UserManagementInterceptor(),             RequestLoggingInterceptor(),             NetworkFetchInterceptor(client: self.client),             ResponseLoggingInterceptor(),             ResponseCodeInterceptor(),             JSONResponseParsingInterceptor(cacheKeyForObject: self.store.cacheKeyForObject),             AutomaticPersistedQueryInterceptor(),             CacheWriteInterceptor(store: self.store)         ]     } }  class HasuraClient {   static let shared = HasuraClient()      private(set) lazy var apollo: ApolloClient = {       \/\/ The cache is necessary to set up the store, which we're going to hand to the provider       let cache = InMemoryNormalizedCache()       let store = ApolloStore(cache: cache)              let client = URLSessionClient()       let provider = NetworkInterceptorProvider(store: store, client: client)       let url = URL(string: \"https:\/\/host.hasura.app\/v1\/graphql\")!     let headers =  [\"x-hasura-admin-secret\": \"your key\"]        let requestChainTransport = RequestChainNetworkTransport(interceptorProvider: provider,                                                                endpointURL: url, additionalHeaders: headers)                                                                        \/\/ Remember to give the store you already created to the client so it       \/\/ doesn't create one on its own       return ApolloClient(networkTransport: requestChainTransport,                           store: store)   }() }<\/code><\/pre>\n<p>  \u0414\u0430, \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0441\u0435\u043f\u0442\u0435\u0440\u043e\u0432, \u0431\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0430\u0448 \u043a\u043e\u0434 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442. \u042d\u0442\u043e \u0441\u043b\u043e\u0436\u043d\u0435\u0435, \u0447\u0435\u043c \u0432 Android, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0438\u043d\u0442\u0435\u0440\u0441\u0435\u043f\u0442\u0435\u0440\u043e\u0432 \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438, \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0432 \u043f\u043e\u0434 \u043d\u0430\u0448\u0443 \u0437\u0430\u0434\u0430\u0447\u0443:  <\/p>\n<pre><code class=\"swift\">import Apollo  class UserManagementInterceptor: ApolloInterceptor {          enum UserError: Error {         case noUserLoggedIn     }          private let headers = [\"x-hasura-admin-secret\": \"your key\"]          \/\/\/ Helper function to add the token then move on to the next step     private func addTokenAndProceed&lt;Operation: GraphQLOperation>(         to request: HTTPRequest&lt;Operation>,         chain: RequestChain,         response: HTTPResponse&lt;Operation>?,         completion: @escaping (Result&lt;GraphQLResult&lt;Operation.Data>, Error>) -> Void) {             for header in headers {                 request.addHeader(name: header.key, value: header.value)             }         chain.proceedAsync(request: request,                            response: response,                            completion: completion)     }          func interceptAsync&lt;Operation: GraphQLOperation>(         chain: RequestChain,         request: HTTPRequest&lt;Operation>,         response: HTTPResponse&lt;Operation>?,         completion: @escaping (Result&lt;GraphQLResult&lt;Operation.Data>, Error>) -> Void) {                     self.addTokenAndProceed(                                     to: request,                                     chain: chain,                                     response: response,                                     completion: completion)     } }  class RequestLoggingInterceptor: ApolloInterceptor {          func interceptAsync&lt;Operation: GraphQLOperation>(         chain: RequestChain,         request: HTTPRequest&lt;Operation>,         response: HTTPResponse&lt;Operation>?,         completion: @escaping (Result&lt;GraphQLResult&lt;Operation.Data>, Error>) -> Void) {                  chain.proceedAsync(request: request,                            response: response,                            completion: completion)     } }  class ResponseLoggingInterceptor: ApolloInterceptor {          enum ResponseLoggingError: Error {         case notYetReceived     }          func interceptAsync&lt;Operation: GraphQLOperation>(         chain: RequestChain,         request: HTTPRequest&lt;Operation>,         response: HTTPResponse&lt;Operation>?,         completion: @escaping (Result&lt;GraphQLResult&lt;Operation.Data>, Error>) -> Void) {                  defer {             \/\/ Even if we can't log, we still want to keep going.             chain.proceedAsync(request: request,                                response: response,                                completion: completion)         }                  guard let receivedResponse = response else {             chain.handleErrorAsync(ResponseLoggingError.notYetReceived,                                    request: request,                                    response: response,                                    completion: completion)             return         }            } }<\/code><\/pre>\n<p>  \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0438\u0445 \u0432 \u043d\u0443\u0436\u043d\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u0440\u0430\u0431\u043e\u0442\u0435 \u043d\u0430\u0434 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438. <br \/>  \u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u043c, \u0447\u0442\u043e UI \u0438 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0443 \u043d\u0430\u0441 \u0433\u043e\u0442\u043e\u0432\u0430.   <\/p>\n<pre><code class=\"swift\"> class AuthHelper {     static let shared = AuthHelper()     private let apollo = HasuraClient.shared.apollo     private weak var userStorage = DI.dataContainer.userStorage          var currentUser: UserData? = nil          \/\/MARK: check authorization     func checkAuth()->Bool {         return currentUser != nil || userStorage?.getUser() != nil     }          func isAuthorized()->Bool {         \/\/Load session and check with saved         return currentUser != nil || userStorage?.getUser() != nil     }          \/\/MARK: Login     func login(email: String, password: String, completion: @escaping(Result&lt;UserData,Error>)->Void) {         apollo.fetch(query:  QueryAdapter.shared.loginUserQuery(email: email, password: password)) { (result:Result&lt;GraphQLResult&lt;GetUserQuery.Data>,Error>) in             switch result {             case .failure(let error):                 print(error)             case .success(let userData):                 if let user = userData.data?.users.first {                     let u = UserData(user: user)                     self.userStorage?.saveUser(data: u)                     completion(.success(u))                                     }             }         }     }          \/\/MARK: registation     func register(name: String, email: String, password: String, completion: @escaping(Result&lt;UserData,Error>)->Void) {         let query = QueryAdapter.shared.createUser(userData: UserData(uid: UUID().uuidString, name: name, email: email, password: password))         apollo.perform(mutation: query){             (result: Result&lt;GraphQLResult&lt;CreateUserMutationMutation.Data>,Error>) in             switch result {             case .failure(let error):                 print(error)                 completion(.failure( error))             case .success(let data):                 if let user = data.data?.insertUsersOne?.fragments.user {                     self.currentUser = UserData(user: user)                     self.userStorage?.saveUser(data: self.currentUser!)                     completion(.success(self.currentUser!))                 }             }         }     } }<\/code><\/pre>\n<p>  \u042d\u0442\u043e \u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0432\u0445\u043e\u0434\u0430 \u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. <br \/>  \u041c\u044b \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u043d\u0430\u0448\u0435\u043c\u0443 apollo ApolooClient \u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b fetch \u0434\u043b\u044f query \u0438\u043b\u0438 perform \u0434\u043b\u044f Mutation \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a API, \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0442\u0438\u043f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0438\u0437 \u043d\u0430\u0448\u0435\u0433\u043e \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u0430.<br \/>  \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u043d\u0430\u043c \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 Result&lt;T,Error>, \u0433\u0434\u0435 T \u2013 \u044d\u0442\u043e GraphQLResult&lt;K.Data> \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 Data \u043a\u043b\u0430\u0441\u0441\u0430, \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0433\u043e \u0432 \u043d\u0430\u0448 Mutation \u0438\u043b\u0438 Query. \u0412\u043d\u0443\u0442\u0440\u0438 Data \u0431\u0443\u0434\u0435\u0442 \u043b\u0438\u0431\u043e \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u0434\u043b\u044f Mutation, \u043b\u0438\u0431\u043e \u043d\u0430\u0431\u043e\u0440 \u043f\u043e\u043b\u0435\u0439 \u043d\u0430\u0448\u0435\u0433\u043e Query. <\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u043f\u0438\u0448\u0435\u043c \u043d\u0430\u0448\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u043f\u043e\u0441\u0442\u0430\u043c\u0438, \u043b\u0430\u0439\u043a\u0430\u043c\u0438 \u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u043c\u0438:  <\/p>\n<pre><code class=\"swift\">class PostService {     private let apollo = HasuraClient.shared.apollo     static let shared = PostService()     private weak var userStorage = DI.dataContainer.userStorage     var currentPosts: [PostItem] = [PostItem]()          \/\/MARK: post     func publishPost(item: PostItem, completion: @escaping(Result&lt;Bool, Error>)->Void) {         guard let user = userStorage?.getUser() else {             return         }         var postItem = item         postItem.userId = user.uid         postItem.userName = user.name         apollo.perform(mutation: QueryAdapter.shared.createPost(postItem: postItem)) {             (result: Result&lt;GraphQLResult&lt;AddPostMutationMutation.Data>,Error>) in             switch result {             case .failure(let error):                 completion(.failure(error))             case .success(_):                 completion(.success(true))             }         }     }      func updatePost(item: PostItem, completion: @escaping(Result&lt;Bool, Error>)->Void) {         guard let user = userStorage?.getUser(), item.userId == user.uid else {             return         }                  let mutation = QueryAdapter.shared.changePost(postItem: item)         apollo.perform(mutation: mutation) {             (result: Result&lt;GraphQLResult&lt;ChangePostMutationMutation.Data>,Error>) in             switch result {             case .failure(let error):                 completion(.failure(error))             case .success(_):                 completion(.success(true))             }         }     }      func deletePost(postId: String,completion: @escaping(Result&lt;Bool, Error>)->Void) {         let mutation = QueryAdapter.shared.deletePostBy(postId: postId)         apollo.perform(mutation: mutation) {             (result: Result&lt;GraphQLResult&lt;DeletePostMutation.Data>,Error>) in             switch result {             case .failure(let error):                 completion(.failure(error))             case .success(_):                 completion(.success(true))             }         }     }          \/\/MARK: posts     func loadPosts(completion: @escaping([PostItem])->Void) {         apollo.fetch(query: PostsQueryQuery()){ [weak self]             (result:Result&lt;GraphQLResult&lt;PostsQueryQuery.Data>,Error>) in             guard let self = self else {return}             switch result {             case .failure(let error):                print(error)             case .success(let data):                 let posts =   data.data?.posts.map{PostItem(data: $0)} ?? [PostItem]()                 completion(self.checkLiked(posts: posts))             }         }     }      private func checkLiked(posts: [PostItem])->[PostItem] {         var tempPosts = posts         guard let userId = userStorage?.getUser()?.uid.lowercased() else {             return posts         }         for i in 0..&lt;tempPosts.count {             let postLikes  = tempPosts[i].likeItems             tempPosts[i].isLiked = (postLikes .filter{$0.userId.lowercased() == userId}).count > 0         }         return tempPosts     }                func changeLike(postItem: PostItem, completion: @escaping(Result&lt;[PostItem],Error>)->Void) {         guard let userId  = userStorage?.getUser()?.uid else {             return         }         var likeItems = postItem.likeItems             if let found = likeItems.filter({$0.userId == userId}).first {                 likeItems.remove(item: found)             } else {             likeItems.append(LikeItem(userId: userId, postId: postItem.uuid))         }         let mutation = ChangeLikeMutationMutation(postId: postItem.uuid.lowercased(), likes: likeItems.map{$0.userId}.joined(separator: \",\"))         apollo.perform(mutation: mutation) {             (result: Result&lt; GraphQLResult&lt;ChangeLikeMutationMutation.Data>,Error>) in             switch result {             case .failure(let error):                 completion(.failure(error))             case .success(_):                 self.loadPosts { items in                     completion(.success(items))                 }             }         }     }          \/\/MARK: comments     func publishComment(item: CommentItem, completion: @escaping(Result&lt;Bool, Error>)->Void) {         var comment = item         guard let user = userStorage?.getUser() else {             return         }         comment.userId = user.uid         comment.userName = user.name         let mutation = item.createComment()         apollo.perform(mutation: mutation) {             (result: Result&lt;GraphQLResult&lt;CreateCommentMutation.Data>,Error>) in             switch result {             case .failure(let error):                 completion(.failure(error))             case .success(_):                 completion(.success(true))                              }         }     }          func loadComments(postId: String, completion: @escaping(Result&lt;[CommentItem], Error>)->Void) {         let query = CommentsQuery(commentId: postId)         apollo.fetch(query: query) {             (result: Result&lt;GraphQLResult&lt;CommentsQuery.Data>,Error>) in             switch result {             case .failure(let error):                 print(error)             case .success(let data):                 let comments = data.data?.comments.map{                     CommentItem(comment: $0)                 } ?? [CommentItem]()                 completion(.success(comments))             }         }     } }<\/code><\/pre>\n<p>  \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0433\u043e\u0442\u043e\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435:<br \/>  <a href=\"https:\/\/github.com\/anioutkazharkova\/graphql_ios_postoram\">github.com\/anioutkazharkova\/graphql_ios_postoram<\/a><\/p>\n<p>  \u041f\u043e\u0434\u0432\u0435\u0434\u0435\u043c \u0438\u0442\u043e\u0433.<\/p>\n<p>  \u0418\u0442\u0430\u043a, \u0437\u0430 3 \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u044b \u0441 \u0432\u0430\u043c\u0438 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0438 \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e\u0435 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0431\u0435\u043a\u0435\u043d\u0434\u043e\u043c \u043d\u0430 GraphQL Hasura. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u043e\u0439 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0435\u0439 \u0432\u0435\u0441\u044c\u043c\u0430 \u0441\u043f\u043e\u0440\u043d\u044b. \u0415\u0441\u043b\u0438 \u043e\u0442\u0432\u043b\u0435\u0447\u044c\u0441\u044f \u043e\u0442 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0439 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 Apollo \u0438 Hasura, \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u2013 \u044d\u0442\u043e \u0432\u044b\u043d\u0443\u0436\u0434\u0435\u043d\u043d\u043e\u0435 \u0438 \u0432\u0435\u0441\u044c\u043c\u0430 \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d\u043e\u0435 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0438\u043f\u043e\u0432 \u0438\u0437-\u0437\u0430 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0432 Query \u0438\u043b\u0438 Mutation. \u0412 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u043c, \u0447\u0442\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c Rest \u0438\u043b\u0438 GraphQL \u2013 \u0443\u0436\u0435 \u0434\u0435\u043b\u043e \u0432\u043a\u0443\u0441\u0430 \u0438 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d\u0438\u0439.<\/p>\n<p>  <b>Bonus. <\/b><br \/>  \u041c\u044b \u0441 \u0432\u0430\u043c\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 Apollo \u0434\u043b\u044f \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u043d\u0430\u0448\u0435\u043c\u0443 API GraphQL \u0423 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438. \u0414\u043b\u044f iOS \u0434\u0430\u0436\u0435 \u043d\u0435\u0442 \u0435\u0449\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 1.0, \u0438 \u0432\u0435\u0440\u0441\u0438\u043e\u043d\u043d\u043e\u0441\u0442\u044c \u043d\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u0430.<br \/>  \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0448 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 json body POST. C\u0434\u0435\u043b\u0430\u0435\u043c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 Payload \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 body.<\/p>\n<p>  \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u0441\u0442\u043e\u0432:   <\/p>\n<pre><code class=\"swift\"> let query = \"\"\" query Posts {   posts {        user_name       user_id       post_text       post_id       post_date       likes       image_link   } } \"\"\"   class NetworkClient {     lazy var urlSession: URLSession? = {         return URLSession(configuration: URLSessionConfiguration.default)     }()          var urlSessionDataTask: URLSessionDataTask? = nil          struct Payload: Encodable {         let query: String     }          private let headers = [\"x-hasura-admin-secret\": \"your key\"]          func doQuery() {         guard let url = URL(string: \"https:\/\/host.hasura.app\/v1\/graphql\") else {             return         }         var urlRequest = URLRequest(url: url)         for header in headers {             urlRequest.addValue(header.value, forHTTPHeaderField: header.key)         }         urlRequest.httpMethod = \"POST\"         urlRequest.httpBody = try? JSONEncoder().encode(Payload(query: query))         let task = self.urlSession?.dataTask(with: urlRequest, completionHandler: { data, response, error in             if let data = data {                 let json = String(data: data, encoding: .utf8)                 print(json) \/\/\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0441\u044e\u0434\u0430             }         })         task?.resume()     } }<\/code><\/pre>\n<p>  \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043d\u0430\u043c \u0432\u0435\u0440\u043d\u0435\u0442 json c \u043a\u043e\u0440\u043d\u0435\u0432\u044b\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c data:  <\/p>\n<pre><code class=\"swift\">\"{ \"data\": { \"posts\": [ { \"user_name\": \"...\", \"user_id\": \"...\", \"post_text\": \"...\", \"post_id\": \"...\", \/\/... } ] } }\"<\/code><\/pre>\n<p>  \u041c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043f\u0430\u0440\u0441\u0435\u0440 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0431\u0435\u0437 Apollo. <br \/>  \u0414\u0435\u0440\u0437\u0430\u0439\u0442\u0435)<\/p>\n<p>  <a href=\"https:\/\/www.apollographql.com\/docs\/ios\/\">www.apollographql.com\/docs\/ios<\/a><br \/>  <a href=\"https:\/\/github.com\/apollographql\/apollo-ios\">github.com\/apollographql\/apollo-ios<\/a><br \/>  <a href=\"https:\/\/github.com\/anioutkazharkova\/graphql_ios_postoram\">github.com\/anioutkazharkova\/graphql_ios_postoram<\/a><\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/645787\/\"> https:\/\/habr.com\/ru\/articles\/645787\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/x3\/za\/hx\/x3zahxlnt9x9jjlzewyixoyphck.png\" data-src=\"https:\/\/habrastorage.org\/webt\/x3\/za\/hx\/x3zahxlnt9x9jjlzewyixoyphck.png\"\/><\/p>\n<p>  <i>\u0414\u043e\u0431\u0440\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0443\u0442\u043e\u043a! \u0421 \u0432\u0430\u043c\u0438 \u0410\u043d\u043d\u0430 \u0416\u0430\u0440\u043a\u043e\u0432\u0430, \u0432\u0435\u0434\u0443\u0449\u0438\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438\u00a0Usetech, \u0438 \u043c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u043d\u0430\u0448\u0443 \u0441\u0435\u0440\u0438\u044e \u0441\u0442\u0430\u0442\u0435\u0439, \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u044b\u0445 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0435\u0439\u00a0GraphQL\u00a0\u00a0\u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. <\/i><\/p>\n<p>  \u0412 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0447\u0430\u0441\u0442\u044f\u0445 \u043c\u044b \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/usetech\/blog\/645273\/\">\u043e \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0435 \u043e\u0431\u043b\u0430\u0447\u043d\u043e\u0433\u043e\u00a0GraphQL\u00a0\u0431\u0435\u043a\u0435\u043d\u0434\u0430 \u043d\u0430\u00a0Hasura<\/a>\u00a0\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/usetech\/blog\/645789\/\">\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438\u00a0GraphQL\u00a0API\u00a0\u043a\u00a0Android\u00a0\u043a\u043b\u0438\u0435\u043d\u0442\u0443<\/a>. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0441\u0442\u0430\u043b \u0447\u0435\u0440\u0435\u0434\u00a0iOS\u00a0\u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. <\/p>\n<p>  \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u00a0Apollo\u00a0GraphQL\u00a0\u0434\u043b\u044f\u00a0iOS:<\/p>\n<p>  <a href=\"https:\/\/www.apollographql.com\/docs\/ios\/\">www.apollographql.com\/docs\/ios<\/a><\/p>\n<p>  <a href=\"https:\/\/github.com\/apollographql\/apollo-ios\">github.com\/apollographql\/apollo-ios<\/a><\/p>\n<p>  \u041d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e\u0435\u00a0Android\u00a0\u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u0442\u0430\u043a\u0438\u0435 \u0436\u0435 \u043f\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0443 \u044d\u043a\u0440\u0430\u043d\u044b:<\/p>\n<p>   \u2014 \u0432\u0445\u043e\u0434<\/p>\n<p>   \u2014 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f<\/p>\n<p>   \u2014 \u043b\u0435\u043d\u0442\u0430 \u043f\u043e\u0441\u0442\u043e\u0432<\/p>\n<p>   \u2014 \u044d\u043a\u0440\u0430\u043d \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u0430<\/p>\n<p>   \u2014 \u044d\u043a\u0440\u0430\u043d \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-408867","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/408867","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=408867"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/408867\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=408867"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=408867"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=408867"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}