Skip to content

Getting Started

Maxwell edited this page Jun 28, 2020 · 2 revisions

Getting Started

Create a retrofit interface method and annotate them with the @GraphQuery annotation using the name of the .graphql file name as the value parameter. e.g.

internal enum class EndpointType(val url: HttpUrl) {
    GITHUB(BuildConfig.github.toHttpUrl()),
    BUCKET(BuildConfig.bucket.toHttpUrl());

    companion object {
        const val BASE_ENDPOINT_PATH = "/graphql"
    }
}

internal interface MarketPlaceRemoteSource {

    @POST(EndpointType.BASE_ENDPOINT_PATH)
    @GraphQuery("GetMarketPlaceApps")
    suspend fun getMarketPlaceApps(
        @Body builder: QueryContainerBuilder
    ): Response<GraphContainer<MarketPlaceListings>>
}   

The model creation is up to the developer, this is where retrofit-graphql differs from apollo, this way you can design your models in anyway you desire. There are tools available to aid in the task of creating models from JSON.

For Kotlin there is JSON To Kotlin Class, a plugin for the IDEA product family. There are also numerous tools available online e.g jsonschema2pojo. One can always start from there and then modify the automatically generated output.

By default the library supplies you with a QueryContainerBuilder which is a holder for your GraphQL variables, operations and request. Also two basic top level models, which you don't have to use if you want to design your own:

QueryContainerBuilder

Suggest using this as is, but if you want to make your own that's not a problem either. The QueryContainerBuilder is used as follows:

Given a .graphql files such as the following:

query GetMarketPlaceApps($first: Int, $after: String, $before: String) {
    marketplaceListings(first: $first, after: $after, before: $before) {
        edges {
            cursor
            node {
                ... MarketPlaceListingCore
            }
        }
        pageInfo {
            ... PageInfo
        }
        totalCount
    }
}

Adding parameters to the request would be done as follows:

val queryBuilder = QueryContainerBuilder()
            .putVariable("first", 15)
// or alternatively you can add a map
val queryBuilder = QueryContainerBuilder()
            .putVariables(
                mapOf(
                    "first" to 15,
                    "after" to "some_cursor_id"
                )
            )

The QueryContainerBuilder is then passed into your retrofit interface method as a parameter and that's it! Just like you would with any ordinary retrofit method.

GraphError

Common GraphQL error that makes use of extension functions

/**
 * Converts the response error response into an object.
 *
 * @return The error object, or null if an exception was encountered
 *
 * @see GraphError
 */
fun Response<*>?.getError(): List<GraphError>? {
    try {
        if (this != null) {
            val responseBody = errorBody()
            val message = responseBody?.string()
            if (responseBody != null && !message.isNullOrBlank()) {
                val graphErrors= message.getGraphQLError()
                if (graphErrors != null)
                    return graphErrors
            }
        }
    } catch (ex: Exception) {
        ex.printStackTrace()
    }
    return null
}

@Throws(JsonSyntaxException::class)
private fun String.getGraphQLError(): List<GraphError>? {
    val tokenType = object : TypeToken<GraphContainer<*>>() {}.type
    val graphContainer = Gson().fromJson<GraphContainer<*>>(this, tokenType)
    return graphContainer.errors
}

GraphContainer

Similar to the top level GraphQL response, but the data type is generic to allow easy reuse.

data class GraphContainer<T>(
    val data: T? = null,
    val errors: List<GraphError>? = null,
    val extensions: Map<Any, Any>? = null
)
Clone this wiki locally