All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.com.apollographql.apollo3.api.internal.ResponseParser.kt Maven / Gradle / Ivy

There is a newer version: 4.0.0-beta.7
Show newest version
package com.apollographql.apollo3.api.internal

import com.apollographql.apollo3.api.ApolloResponse
import com.apollographql.apollo3.api.CustomScalarAdapters
import com.apollographql.apollo3.api.DeferredFragmentIdentifier
import com.apollographql.apollo3.api.Error
import com.apollographql.apollo3.api.Operation
import com.apollographql.apollo3.api.falseVariables
import com.apollographql.apollo3.api.json.JsonReader
import com.apollographql.apollo3.api.json.MapJsonReader
import com.apollographql.apollo3.api.json.readAny
import com.apollographql.apollo3.api.parseData
import com.benasher44.uuid.Uuid
import com.benasher44.uuid.uuid4

/**
 * [ResponseParser] parses network responses, including data, errors and extensions from a [JsonReader]
 */
internal object ResponseParser {
  fun  parse(
      jsonReader: JsonReader,
      operation: Operation,
      requestUuid: Uuid?,
      customScalarAdapters: CustomScalarAdapters,
      deferredFragmentIds: Set?,
  ): ApolloResponse {
    jsonReader.beginObject()

    var data: D? = null
    var errors: List? = null
    var extensions: Map? = null
    while (jsonReader.hasNext()) {
      @Suppress("UNCHECKED_CAST")
      when (jsonReader.nextName()) {
        "data" -> {
          val falseVariables = operation.falseVariables(customScalarAdapters)
          data = operation.parseData(jsonReader, customScalarAdapters, falseVariables, deferredFragmentIds, errors)
        }
        "errors" -> errors = jsonReader.readErrors()
        "extensions" -> extensions = jsonReader.readAny() as? Map
        else -> jsonReader.skipValue()
      }
    }

    jsonReader.endObject()

    return ApolloResponse.Builder(operation = operation, requestUuid = requestUuid ?: uuid4())
        .errors(errors)
        .data(data)
        .extensions(extensions)
        .build()
  }

  fun parseError(
      payload: Map,
  ) = MapJsonReader(payload).readError()

  private fun JsonReader.readErrors(): List {
    if (peek() == JsonReader.Token.NULL) {
      nextNull()
      return emptyList()
    }

    beginArray()
    val list = mutableListOf()
    while (hasNext()) {
      list.add(readError())
    }
    endArray()
    return list
  }

  @Suppress("UNCHECKED_CAST")
  private fun JsonReader.readError(): Error {
    var message = ""
    var locations: List? = null
    var path: List? = null
    var extensions: Map? = null
    var nonStandardFields: MutableMap? = null
    beginObject()
    while (hasNext()) {
      when (val name = nextName()) {
        "message" -> message = nextString() ?: ""
        "locations" -> {
          locations = readErrorLocations()
        }

        "path" -> {
          path = readPath()
        }

        "extensions" -> {
          extensions = readAny() as? Map?
        }

        else -> {
          if (nonStandardFields == null) nonStandardFields = mutableMapOf()
          nonStandardFields[name] = readAny()
        }
      }
    }
    endObject()


    @Suppress("DEPRECATION")
    return Error(message, locations, path, extensions, nonStandardFields)
  }

  private fun JsonReader.readPath(): List? {
    if (peek() == JsonReader.Token.NULL) {
      return nextNull()
    }

    val list = mutableListOf()
    beginArray()
    while (hasNext()) {
      when (peek()) {
        JsonReader.Token.NUMBER, JsonReader.Token.LONG -> list.add(nextInt())
        else -> list.add(nextString()!!)
      }
    }
    endArray()

    return list
  }

  private fun JsonReader.readErrorLocations(): List? {
    if (peek() == JsonReader.Token.NULL) {
      return nextNull()
    }
    val list = mutableListOf()
    beginArray()
    while (hasNext()) {
      list.add(readErrorLocation())
    }
    endArray()

    return list
  }

  private fun JsonReader.readErrorLocation(): Error.Location {
    var line: Int = -1
    var column: Int = -1
    beginObject()
    while (hasNext()) {
      when (nextName()) {
        "line" -> line = nextInt()
        "column" -> column = nextInt()
        else -> skipValue()
      }
    }
    endObject()
    return Error.Location(line, column)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy