{"id":328211,"date":"2022-01-18T15:01:04","date_gmt":"2022-01-18T15:01:04","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=328211"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=328211","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 Android<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" 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 Usetech, \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 GraphQL \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\u043e\u0448\u043b\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \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 GraphQL \u0431\u0435\u043a\u0435\u043d\u0434\u0430 \u043d\u0430 Hasura<\/a>. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044e GraphQL \u0438 API \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e. \u0418 \u043d\u0430\u0447\u043d\u0435\u043c \u043c\u044b \u0441 Android \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<p>  <a href=\"https:\/\/github.com\/apollographql\/apollo-android\">github.com\/apollographql\/apollo-android<\/a><br \/>  <a href=\"https:\/\/www.apollographql.com\/docs\/android\/\">www.apollographql.com\/docs\/android<\/a><\/p>\n<p>  \u041d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432:<\/p>\n<ul>\n<li>\u0432\u0445\u043e\u0434<\/li>\n<li>\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f<\/li>\n<li>\u043b\u0435\u043d\u0442\u0430 \u043f\u043e\u0441\u0442\u043e\u0432<\/li>\n<li>\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<\/li>\n<li>\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.<\/li>\n<\/ul>\n<p>  \u042d\u043a\u0440\u0430\u043d\u044b \u0438 \u0441\u043e\u043f\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u0443\u0436\u0435 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c, \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c API.<br \/>  \u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u044b \u0445\u0440\u0430\u043d\u0438\u043c \u0432 Firebase Storage, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u0437\u0430\u0442\u0440\u0430\u0433\u0438\u0432\u0430\u0435\u043c \u044d\u0442\u043e\u0442 \u0432\u043e\u043f\u0440\u043e\u0441.<br \/>  <a name=\"habracut\"><\/a><br \/>  <img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/webt\/pu\/0x\/jt\/pu0xjtvpheu-gnn6ibspcv1thm8.png\" data-width=\"30%\"\/><\/p>\n<p>  <img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/webt\/ui\/pi\/ld\/uipild72ete7x5fhqipiusqme7i.png\" data-width=\"30%\"\/><\/p>\n<p>  <img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/webt\/bu\/k8\/lo\/buk8lotpfjzxdhfwdfqmzat9i2e.png\" data-width=\"30%\"\/><\/p>\n<p>  <img decoding=\"async\" src=\"\/img\/image-loader.svg\" data-src=\"https:\/\/habrastorage.org\/webt\/1l\/9l\/yu\/1l9lyul97sh4jb-t81gkxzjlowe.png\" data-width=\"30%\"\/><\/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 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 apollo \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 GraphQL \u043f\u043e\u0434 android, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043d\u0430\u0448 build.gradle:<\/p>\n<p>  implementation(\u00abcom.apollographql.apollo:apollo-runtime:2.5.9\u00bb)<br \/>  implementation(\u00abcom.apollographql.apollo:apollo-coroutines-support:2.5.9\u00bb)<\/p>\n<p>  \u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430\u043c\u0438, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442\u044c \u0441\u0435\u0431\u0435 \u0437\u0430\u0434\u0430\u0447\u0443 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u044b \u0435\u0449\u0435 \u043d\u0435 \u0432\u044b\u043a\u0430\u0447\u0430\u043b\u0438 \u0441\u0445\u0435\u043c\u0443, \u0442\u043e \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u044d\u0442\u043e \u0441\u0435\u0439\u0447\u0430\u0441. \u041c\u043e\u0436\u043d\u043e \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u043a\u0430\u043a \u0431\u044b\u043b\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438:<\/p>\n<pre><code class=\"swift\">npm i apollo-codegen   apollo-codegen download-schema \"&lt;host>.hasura.app\/v1\/graphql\"  --output schema.json --header \"x-hasura-admin-secret: &lt;key>\"<\/code><\/pre>\n<p>  \u041b\u0438\u0431\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 gradle:<\/p>\n<pre><code class=\"swift\">.\/gradlew downloadApolloSchema \\   --endpoint=\"&lt;host>.hasura.app\/v1\/graphql\" \\   --schema=\".\/app\/src\/main\/graphql\/com\/ex2\/hasura\/gql\/schema.json\" \\   --header=\"x-hasura-admin-secret: &lt;key>\"<\/code><\/pre>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043d\u0444\u0438\u0433 \u043f\u043e \u043f\u0443\u0442\u0438 main\/graphql\/com\/ex2\/hasura\/gql c \u0438\u043c\u0435\u043d\u0435\u043c .graphqlconfig:<\/p>\n<pre><code class=\"swift\">{   \"name\": \"Expenses Schema\",   \"schemaPath\": \"schema.json\",   \"extensions\": {     \"endpoints\": {       \"Default GraphQL Endpoint\": {         \"url\": \"&lt;host>\/v1\/graphql\",         \"headers\": {           \"user-agent\": \"JS GraphQL\",           \"x-hasura-admin-secret\" : \"&lt;key>\"         },         \"introspect\": false       }     }   } }<\/code><\/pre>\n<p>  \u0412 \u043a\u043e\u043d\u0444\u0438\u0433\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043f\u0443\u0442\u044c \u043a \u043d\u0430\u0448\u0435\u043c\u0443 API \u0438 \u043a\u043b\u044e\u0447 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438. <\/p>\n<p>  \u0412 \u044d\u0442\u043e\u0442 \u0436\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u043f\u043e\u043b\u043e\u0436\u0438\u043c \u043d\u0430\u0448\u0443 schema.json. <\/p>\n<p>  \u0412\u0441\u0435 \u043d\u0430\u0448\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b\u0438 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438, \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0432 \u0444\u0430\u0439\u043b \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c .graphql:<\/p>\n<pre><code class=\"swift\"> query PostsQuery {     posts {         ... Post     } }  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     } }  query GetPostQuery($postId: uuid) {     posts(where: {post_id: {_eq: $postId}}) {         ... Post     }     likes(where: {post_id: {_eq: $postId}}){         ... LikeForPost     }     comments(where: {post_id: {_eq: $postId}}){         ... Comment     } }  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 User($email: String, $password: String) {     users(where: {password: {_eq: $password}, user_email: {_eq: $email}}) {        ... User     } }  query Likes($postId: uuid) {     likes(where: {post_id: {_eq: $postId}}){         ... LikeForPost     } }  query Comments($commentId: uuid) {     comments(where: {post_id: {_eq: $commentId}}) {         ... Comment     } }  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>  \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0443 nullable \u043f\u043e\u043b\u0435\u0439 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c! \u0434\u043b\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438. \u0422\u0430\u043a\u0436\u0435 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u0432 \u0432\u044b\u0434\u0430\u0447\u0443 query \u0438 mutation. <\/p>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 build \u0434\u043b\u044f \u0442\u0438\u043f\u043e\u0432 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043e\u0432 \u0443 \u043d\u0430\u0441 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<pre><code class=\"kotlin\">\/\/\u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430 \u0434\u043b\u044f \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432 @Suppress(\"NAME_SHADOWING\", \"UNUSED_ANONYMOUS_PARAMETER\", \"LocalVariableName\",     \"RemoveExplicitTypeArguments\", \"NestedLambdaShadowedImplicitParameter\") data class Comment(   val __typename: String = \"comments\",   val comment_id: Any,   val comment_text: String,   val user_id: Any,   val post_id: Any,   val user_name: String? ) : GraphqlFragment {   override fun marshaller(): ResponseFieldMarshaller = ResponseFieldMarshaller.invoke { writer ->     writer.writeString(RESPONSE_FIELDS[0], this@Comment.__typename)     writer.writeCustom(RESPONSE_FIELDS[1] as ResponseField.CustomTypeField, this@Comment.comment_id)     writer.writeString(RESPONSE_FIELDS[2], this@Comment.comment_text)     writer.writeCustom(RESPONSE_FIELDS[3] as ResponseField.CustomTypeField, this@Comment.user_id)     writer.writeCustom(RESPONSE_FIELDS[4] as ResponseField.CustomTypeField, this@Comment.post_id)     writer.writeString(RESPONSE_FIELDS[5], this@Comment.user_name)   }    companion object {     private val RESPONSE_FIELDS: Array&lt;ResponseField> = arrayOf(         ResponseField.forString(\"__typename\", \"__typename\", null, false, null),         ResponseField.forCustomType(\"comment_id\", \"comment_id\", null, false, CustomType.UUID, null),         ResponseField.forString(\"comment_text\", \"comment_text\", null, false, null),         ResponseField.forCustomType(\"user_id\", \"user_id\", null, false, CustomType.UUID, null),         ResponseField.forCustomType(\"post_id\", \"post_id\", null, false, CustomType.UUID, null),         ResponseField.forString(\"user_name\", \"user_name\", null, true, null)         )      val FRAGMENT_DEFINITION: String = \"\"\"         |fragment Comment on comments {         |  __typename         |  comment_id         |  comment_text         |  user_id         |  post_id         |  user_name         |}         \"\"\".trimMargin()      operator fun invoke(reader: ResponseReader): Comment = reader.run {       val __typename = readString(RESPONSE_FIELDS[0])!!       val comment_id = readCustomType&lt;Any>(RESPONSE_FIELDS[1] as ResponseField.CustomTypeField)!!       val comment_text = readString(RESPONSE_FIELDS[2])!!       val user_id = readCustomType&lt;Any>(RESPONSE_FIELDS[3] as ResponseField.CustomTypeField)!!       val post_id = readCustomType&lt;Any>(RESPONSE_FIELDS[4] as ResponseField.CustomTypeField)!!       val user_name = readString(RESPONSE_FIELDS[5])       Comment(         __typename = __typename,         comment_id = comment_id,         comment_text = comment_text,         user_id = user_id,         post_id = post_id,         user_name = user_name       )     }      @Suppress(\"FunctionName\")     fun Mapper(): ResponseFieldMapper&lt;Comment> = ResponseFieldMapper { invoke(it) }   } }<\/code><\/pre>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 enum \u0434\u043b\u044f \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u043e\u0432:<\/p>\n<pre><code class=\"kotlin\">enum class CustomType : ScalarType {   ID {     override fun typeName(): String = \"ID\"      override fun className(): String = \"kotlin.String\"   },    _UUID {     override fun typeName(): String = \"_uuid\"      override fun className(): String = \"kotlin.Any\"   },    DATE {     override fun typeName(): String = \"date\"      override fun className(): String = \"kotlin.Any\"   },    UUID {     override fun typeName(): String = \"uuid\"      override fun className(): String = \"kotlin.Any\"   } }<\/code><\/pre>\n<p>  \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441\u0432\u043e\u0439 \u0444\u0430\u0439\u043b \u0441 \u043c\u0430\u043f\u0438\u043d\u0433\u043e\u043c \u043f\u043e\u043b\u0435\u0439 \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043e\u0442\u0432\u0435\u0442\u0430. \u041a\u0430\u0436\u0434\u044b\u0439 \u043d\u0430\u0448 \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0432 \u0441\u0432\u043e\u0439 \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438:<\/p>\n<pre><code class=\"kotlin\">@Suppress(\"NAME_SHADOWING\", \"UNUSED_ANONYMOUS_PARAMETER\", \"LocalVariableName\",     \"RemoveExplicitTypeArguments\", \"NestedLambdaShadowedImplicitParameter\") class PostsQuery : Query&lt;PostsQuery.Data, PostsQuery.Data, Operation.Variables> {   override fun operationId(): String = OPERATION_ID   override fun queryDocument(): String = QUERY_DOCUMENT   override fun wrapData(data: Data?): Data? = data   override fun variables(): Operation.Variables = Operation.EMPTY_VARIABLES   override fun name(): OperationName = OPERATION_NAME   override fun responseFieldMapper(): ResponseFieldMapper&lt;Data> = ResponseFieldMapper.invoke {     Data(it)   }    @Throws(IOException::class)   override fun parse(source: BufferedSource, scalarTypeAdapters: ScalarTypeAdapters): Response&lt;Data>       = SimpleOperationResponseParser.parse(source, this, scalarTypeAdapters)    @Throws(IOException::class)   override fun parse(byteString: ByteString, scalarTypeAdapters: ScalarTypeAdapters): Response&lt;Data>       = parse(Buffer().write(byteString), scalarTypeAdapters)    @Throws(IOException::class)   override fun parse(source: BufferedSource): Response&lt;Data> = parse(source, DEFAULT)    @Throws(IOException::class)   override fun parse(byteString: ByteString): Response&lt;Data> = parse(byteString, DEFAULT)    override fun composeRequestBody(scalarTypeAdapters: ScalarTypeAdapters): ByteString =       OperationRequestBodyComposer.compose(     operation = this,     autoPersistQueries = false,     withQueryDocument = true,     scalarTypeAdapters = scalarTypeAdapters   )    override fun composeRequestBody(): ByteString = OperationRequestBodyComposer.compose(     operation = this,     autoPersistQueries = false,     withQueryDocument = true,     scalarTypeAdapters = DEFAULT   )   \/\/\u2026. }<\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c\u0443 \u2013 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430. \u0411\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c ApolloClient. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u0435\u0442\u044c\u044e \u043e\u043d \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 okHttpClient. <\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u0439 Interceptor \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043d\u0435 \u0432\u0441\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c. <\/p>\n<pre><code class=\"kotlin\">class HerasuClient {      val apolloClient: ApolloClient by lazy {         setupApollo()     }     companion object {         val instance = HerasuClient()     }      private class AuthorizationInterceptor(): Interceptor {         override fun intercept(chain: Interceptor.Chain): Response {             val request = chain.request().newBuilder()                 .addHeader(\"x-hasura-admin-secret\", \"&lt;key>\")                 .build()              return chain.proceed(request)         }     }       private fun setupApollo(): ApolloClient {         return ApolloClient.builder()             .serverUrl(\"&lt;host>.app\/v1\/graphql\")             .okHttpClient(OkHttpClient.Builder()                 .addInterceptor(AuthorizationInterceptor())                 .build()             )             .build()     } }<\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044e \u043d\u0430\u0448\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0443 \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438. <\/p>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0438 \u0432\u0445\u043e\u0434\u043d\u044b\u0435 \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432 Query \u0438 Mutation. \u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u0444\u0430\u0439\u043b\u0435 graphql \u0443 \u043d\u0430\u0441 \u0441\u043e\u0437\u0434\u0430\u043b\u0441\u044f \u0441\u0432\u043e\u0439 \u0442\u0438\u043f \u0441 \u043f\u043e\u043b\u044f\u043c\u0438.<\/p>\n<pre><code class=\"kotlin\">class QueryAdapter {     companion object {         val instance = QueryAdapter()     }      fun loginUserQuery(email: String, password: String): UserQuery {         return UserQuery(Input.optional(email), Input.optional(password))     }      fun loginUserQuery(userData: UserData): UserQuery {         return UserQuery(Input.optional(userData.email), Input.optional(userData.password))     }      fun createUser(userData: UserData):CreateUserMutation {        return CreateUserMutation(name = Input.optional(userData.name), id = Input.optional(UUID.randomUUID()), email = Input.optional(userData.email), password = Input.optional(userData.password))     }      fun createPost(postItem: PostItem):AddPostMutation {         return AddPostMutation(             postId = Input.optional(UUID.fromString(postItem.uuid)),             text = Input.optional(postItem.postText),             user = Input.optional(postItem.userName),             userId = Input.optional(UUID.fromString(postItem.userId)),             date = Input.optional(Date()),             image = Input.optional(postItem.imageLink.orEmpty())         )     }      fun changeLike(postItem: PostItem):ChangeLikeMutation {         val likes = postItem.mapLikes()         return  ChangeLikeMutation(postId = Input.optional(UUID.fromString(postItem.uuid)), likes = Input.optional(likes))     }      fun changePost(postItem: PostItem):ChangePostMutation {         return ChangePostMutation(postId = Input.optional(UUID.fromString(postItem.uuid)), postText = Input.optional(postItem.postText),imageLink = Input.optional(postItem.imageLink))     }      fun deletePost(postItem: PostItem):DeletePostMutation {         return DeletePostMutation(Input.optional(postItem.uuid))     }      fun createComment(commentItem: CommentItem):CreateCommentMutation {         return CreateCommentMutation(postId = Input.optional(UUID.fromString(commentItem.postId)), userId = Input.optional(UUID.fromString(commentItem.userId)),commentText = Input.optional(commentItem.text), id = Input.optional(UUID.randomUUID()),userName = Input.optional(commentItem.userName))     }  }<\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435. \u0412\u0441\u0435 \u043d\u0430\u0448\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0443\u043a\u0430\u0437\u0430\u043b\u0438. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u044d\u0442\u043e, \u043a\u0430\u043a \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442, \u043e\u0434\u043d\u0430 \u0438 \u0442\u0430 \u0436\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0438\u0437-\u0437\u0430 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u044d\u0442\u043e \u0440\u0430\u0437\u043d\u044b\u0435 \u0442\u0438\u043f\u044b. <\/p>\n<p>  \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043d\u0430\u0448\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0432\u043e\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"kotlin\">fun PostItem.mapLikes():String {     val likeString = likeItems.map { it.userId }     return likeString.joinToString(\", \") }  fun PostsQuery.Post.toPost():PostItem{     val post = this.fragments.post     var postItem = PostItem()     postItem.uuid = (post.post_id as? String).orEmpty()     postItem.userName = post.user_name.orEmpty()     postItem.userId = (post.user_id as? String).orEmpty()     postItem.date = (post.date as? Date)?.format(\"HH:mm dd.MM.yyyy\").orEmpty()     postItem.postText = post.post_text.orEmpty()     if (post.likes != null) {         postItem.likeItems = (post.likes as? String)?.split(\",\")?.orEmpty()?.map {             val like = LikeItem()             like.userId = it             like.postId = post.post_id.toString()             like         } as ArrayList&lt;LikeItem>     } else {         postItem.likeItems = arrayListOf()     }     postItem.imageLink = post.image_link.orEmpty()     return postItem }  fun GetPostQuery.Post.toPost():PostItem{     val post = this.fragments.post     var postItem = PostItem()     postItem.uuid = (post.post_id as? String).orEmpty()     postItem.userName = post.user_name.orEmpty()     postItem.userId = (post.user_id as? String).orEmpty()     postItem.date = (post.date as? Date)?.format(\"HH:mm dd.MM.yyyy\").orEmpty()     postItem.postText = post.post_text.orEmpty()     if (post.likes != null) {         postItem.likeItems = (post.likes as? String)?.split(\",\")?.orEmpty()?.map {             val like = LikeItem()             like.userId = it             like.postId = post.post_id.toString()             like         }.orEmpty() as ArrayList&lt;LikeItem>     } else {         postItem.likeItems = arrayListOf()     }     postItem.imageLink = post.image_link.orEmpty()     return postItem }  fun AddPostMutation.Insert_posts_one.Fragments.toPost():PostItem{     val post = this.post     var postItem = PostItem()     postItem.uuid = (post.post_id as? String).orEmpty()     postItem.userName = post.user_name.orEmpty()     postItem.userId = (post.user_id as? String).orEmpty()     postItem.date = (post.date as? Date)?.format(\"HH:mm dd.MM.yyyy\").orEmpty()     postItem.postText = post.post_text.orEmpty()     postItem.likeItems = arrayListOf()     postItem.imageLink = post.image_link.orEmpty()     return postItem }  fun UserQuery.User.toUserData():UserData {     val user = this.fragments.user     val uuid =  (user.user_id as? String)?.let { UUID.fromString(it) } ?: UUID.randomUUID()     val name = user.user_name     val email = user.user_email     return UserData(uuid,name,email,\"\") }  fun CreateUserMutation.Insert_users_one.Fragments.toUserData():UserData {     val user = this.user     val uuid = (user.user_id as? String)?.let { UUID.fromString(it) } ?: UUID.randomUUID()     val name = user.user_name     val email = user.user_email     return UserData(uuid,name,email,\"\") }  fun CommentsQuery.Comment.toComment(): CommentItem {       val comment =  this.fragments.comment         val commentItem = CommentItem()         commentItem.uuid = (comment.comment_id as? String).orEmpty()         commentItem.text = comment.comment_text         commentItem.userId = (comment.user_id as? String).orEmpty()        commentItem.userName = comment.user_name.orEmpty()         commentItem.postId = (comment.post_id as? String).orEmpty()         return commentItem }  fun CreateCommentMutation.Insert_comments_one.toComment(): CommentItem {     val comment =  this.fragments.comment     val commentItem = CommentItem()     commentItem.uuid = (comment.comment_id as? String).orEmpty()     commentItem.text = comment.comment_text     commentItem.userId = (comment.user_id as? String).orEmpty()     commentItem.userName = comment.user_name.orEmpty()     commentItem.postId = (comment.post_id as? String).orEmpty()     return commentItem }<\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043d\u044f\u0442\u044c\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438. \u0414\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 query \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443 apolloClient.query, \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0432\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043d\u0430\u0448 \u0442\u0438\u043f Query. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c await \u0434\u043b\u044f \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u0432 suspend. \u0412\u043d\u0443\u0442\u0440\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0431\u0449\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 data, \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0443\u0442 \u0442\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u043b\u0438 \u0432 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0445 \u0435\u0449\u0435 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 GraphQL \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0441 mutation.<\/p>\n<pre><code class=\"kotlin\">suspend  fun loginUser(email: String, password: String): Result&lt;UserData> {    val response = apolloClient.query(QueryAdapter.instance.loginUserQuery(email, password)).await()     response.data?.users?.firstOrNull()?.let {         currentUser = it.toUserData()     }     val error = response.errors?.firstOrNull()?.message     if (currentUser != null) {         return Result.Success(currentUser!!)     } else {         return Result.Error(Exception(error))     } }  suspend fun createUser(user: UserData): Result&lt;UserData> {     val newUser = QueryAdapter.instance.createUser(user)     val response =  apolloClient.mutate(newUser).await()     val userData = response.data?.insert_users_one?.fragments?.toUserData()     val error = response.errors?.firstOrNull()?.message     if (userData != null) {         return Result.Success(userData)     } else {         return Result.Error(Exception(error))     } }<\/code><\/pre>\n<p>  \u041a\u043e\u0434 \u0432\u044b\u0448\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u043b\u044f \u0432\u0445\u043e\u0434\u0430 \u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0435\u0433\u043e \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u043e\u0432:<\/p>\n<pre><code class=\"kotlin\">suspend fun loadPosts(): Result&lt;List&lt;PostItem>> {      val response = apolloClient.query(PostsQuery()).await()      val posts = response.data?.posts?.map { it.toPost() }      val error = response.errors?.firstOrNull()?.message.orEmpty()      if (posts != null) {          return Result.Success(checkLiked(posts))      } else {          return Result.Error(java.lang.Exception(error))      }  }   fun checkLiked(posts: List&lt;PostItem>): List&lt;PostItem> {      val currentUser = AuthRepository.instance.currentUser      if (currentUser != null) {          for (item in posts) {              item.hasLike = item.likeItems.any { it.userId == currentUser.uid.toString() }          }      }      return posts  }   suspend fun loadPost(id: String): Result&lt;PostItem?> {      val postResponse =          apolloClient.query(GetPostQuery(postId = Input.optional(UUID.fromString(id)))).await()      val posts = postResponse.data?.posts?.map { it.toPost() }      val error = postResponse.errors?.firstOrNull()?.message.orEmpty()      if (posts != null) {          return Result.Success(posts.firstOrNull())      } else {          return Result.Error(java.lang.Exception(error))      }  }    suspend fun createPost(postItem: PostItem): Result&lt;PostItem> {      val currentUser = AuthRepository.instance.currentUser      postItem.userId = currentUser?.uid.toString().orEmpty()      postItem.userName = currentUser?.name.orEmpty()       val response = apolloClient.mutate(QueryAdapter.instance.createPost(postItem)).await()      val error = response.errors?.firstOrNull()?.message.orEmpty()      val created = response.data?.insert_posts_one?.fragments?.toPost()      if (created != null) {          return Result.Success(created)      } else {          return Result.Error(java.lang.Exception(error))      }  }  suspend fun changeLike(postItem: PostItem):Result&lt;Boolean> {      val currentUser = AuthRepository.instance.currentUser      if (currentUser != null) {          val uuid = currentUser.uid          val found = postItem.likeItems.filter { it.userId == uuid.toString() }          if (!found.isNullOrEmpty()) {              postItem.likeItems =                  postItem.likeItems.filter { it.userId != uuid.toString() } as ArrayList&lt;LikeItem>          } else {              val likeItem = LikeItem()              likeItem.postId = postItem.uuid              likeItem.userId = uuid.toString()              postItem.likeItems.add(likeItem)          }        val response =  apolloClient.mutate(             QueryAdapter.instance.changeLike(postItem)          ).await()           val error = response.errors?.firstOrNull()?.message          if (response.data != null) {              return Result.Success(true)          } else {              return Result.Success(false)          }      } else {          return Result.Success(false)      }  }   suspend fun editPost(postItem: PostItem):Result&lt;PostItem> {      val currentUser = AuthRepository.instance.currentUser      if (postItem.userId == currentUser?.uid.toString()) {          val response = apolloClient.mutate(QueryAdapter.instance.changePost(postItem)).await()          val error = response.errors?.firstOrNull()?.message          if (response.data != null) {              return Result.Success(postItem)          } else {              return Result.Error(Exception(error))          }      } else {          return Result.Error(Exception(\"wrong user\"))      }  }  suspend fun deletePost(postItem: PostItem):Result&lt;Boolean> {      val currentUser = AuthRepository.instance.currentUser      if (postItem.userId == currentUser?.uid.toString()) {          val response = apolloClient.mutate(QueryAdapter.instance.deletePost(postItem)).await()          val error = response.errors?.firstOrNull()?.message          if (response.data != null) {              return Result.Success(true)          } else {              return Result.Error(Exception(error))          }       } else {          return Result.Error(Exception(\"wrong user\"))      }  }<\/code><\/pre>\n<p>  \u0418 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432:<\/p>\n<pre><code class=\"kotlin\">suspend fun loadComments(postId: String): Result&lt;List&lt;CommentItem>> {     val response =         apolloClient.query(CommentsQuery(commentId = Input.optional(UUID.fromString(postId))))             .await()     val comments = response.data?.comments?.map { it.toComment() }     val error = response.errors?.firstOrNull()?.message     if (comments != null) {         return Result.Success(comments)     } else {         return Result.Error(Exception(error))     } }   suspend fun sendComment(commentItem: CommentItem):Result&lt;CommentItem> {      val currentUser = AuthRepository.instance.currentUser      commentItem.userId = currentUser?.uid.toString().orEmpty()      commentItem.userName = currentUser?.name.orEmpty()     val response = apolloClient.mutate(QueryAdapter.instance.createComment(commentItem)).await()      val comment = response.data?.insert_comments_one?.toComment()      val error = response.errors?.firstOrNull()?.message      if (comment != null) {          return Result.Success(comment)      } else {          return Result.Error(Exception(error))      }  }<\/code><\/pre>\n<p>  \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043a\u043e\u0434, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u0432\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<p>  <a href=\"https:\/\/github.com\/anioutkazharkova\/android_graphql\">\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435<\/a>.<\/p>\n<p>  \u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c, \u043a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0430 iOS.<\/p>\n<p>  <a href=\"https:\/\/github.com\/apollographql\/apollo-android\">github.com\/apollographql\/apollo-android<\/a><br \/>  <a href=\"https:\/\/www.apollographql.com\/docs\/android\/\">www.apollographql.com\/docs\/android<\/a><\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/usetech\/blog\/645789\/\"> https:\/\/habr.com\/ru\/company\/usetech\/blog\/645789\/<\/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_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"\/img\/image-loader.svg\" 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 Usetech, \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 GraphQL \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\u043e\u0448\u043b\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \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 GraphQL \u0431\u0435\u043a\u0435\u043d\u0434\u0430 \u043d\u0430 Hasura<\/a>. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044e GraphQL \u0438 API \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e. \u0418 \u043d\u0430\u0447\u043d\u0435\u043c \u043c\u044b \u0441 Android \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<p>  <a href=\"https:\/\/github.com\/apollographql\/apollo-android\">github.com\/apollographql\/apollo-android<\/a><br \/>  <a href=\"https:\/\/www.apollographql.com\/docs\/android\/\">www.apollographql.com\/docs\/android<\/a><\/p>\n<p>  \u041d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432:<\/p>\n<ul>\n<li>\u0432\u0445\u043e\u0434<\/li>\n<li>\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f<\/li>\n<li>\u043b\u0435\u043d\u0442\u0430 \u043f\u043e\u0441\u0442\u043e\u0432<\/li>\n<li>\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<\/li>\n<li>\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.<\/li>\n<\/ul>\n<p>  \u042d\u043a\u0440\u0430\u043d\u044b \u0438 \u0441\u043e\u043f\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u0443\u0436\u0435 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c, \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c API.<br \/>  \u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u044b \u0445\u0440\u0430\u043d\u0438\u043c \u0432 Firebase Storage, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u0437\u0430\u0442\u0440\u0430\u0433\u0438\u0432\u0430\u0435\u043c \u044d\u0442\u043e\u0442 \u0432\u043e\u043f\u0440\u043e\u0441.  <\/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-328211","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/328211","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=328211"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/328211\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=328211"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=328211"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=328211"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}