Make generated classes extend common super-type
See original GitHub issueIs your feature request related to a problem? Please describe. I want to create a function where some common transforms/error-handling/logging can live. As of now each class exists independently in the class hierarchy, and thus it is non-trivial to create abstractions with them.
Given the example classes here;
class FetchName(private val graphQLClient: GraphQLClient<*>) { ... } // Generated for fetchName.graphql
class FetchNameBulk(private val graphQLClient: GraphQLClient<*>) { ... } // Generated for fetchNameBulk.graphql
In order to pack some custom-logic in here (mainly custom error-handling and logging) I want to do something like this;
fun exec(query: FetchName, variables: FetchName.Variables): GraphlQLResponse<FetchName.Result>? {
val uuid = UUID.randomUUID();
return try {
val transformedVariables = transform(variables)
servicecallLog.info(uuid, "FetchNameRequest", transformedVariables)
val response = query.execute(transformedVariables)
if (response.errors.isNullOrEmpty()) {
servicecallLog.info(uuid, "FetchNameResponse", response)
response
} else {
servicecallLog.error(uuid, "FetchNameError", response.errors)
null
}
} catch (exception: Exception) {
servicecallLog.error(uuid, "FetchNameError", e)
null
}
}
Now the code can be duplicated and changed to fit for FetchNameBulk
as well, but I would prefer a more generic approach.
Describe the solution you’d like Experimented a bit with the code-generation, and how it could be structured. That way I found that introducing a common super-interface could solve my issues pretty neatly without (as far as I could tell) introducing any adverse effects.
What I propose is something along the lines of;
class FetchName(private val graphQLClient: GraphQLClient<*>) : GraphQLRequestDescription<FetchName.Variables, FetchName.Result> { ... }
That way the exec
function above could be generalize
fun <VARS, RESULT> exec(query: GraphQLRequestDescription<VARS, RESULT>, variables: VARS): GraphQLResponse<RESULT>
Personally I would prefer GraphQLRequest
instead of GraphQLRequestDescription
, but since it’s already used in the types-package I used GraphQLRequestDescription
when testing.
Describe alternatives you’ve considered The “problem” can be though of as three separate issues; variable-transforms, logging and custom-errorhandling.
Errorhandling is trivial to solve as the return-type already has a common return type GraphQLResponse<T>
.
For logging I looked into using ktor-client-logging, but from what I could understand you are pretty limited in what you can do with it. Another possibility is to create a custom HttpClientFeature
, but again it makes it hard to log just the graphql-variables for instance.
Custom variable-transforms could be hoisted to the callsite of the exec
function. But I would then have to rely on every developer to call the transform-function before passing the variables.
Addition context I’ve played around with some code locally, and believe I may have working proof-of-concept (absent the tests). But wanted to create a issue to discuss the feature before diving even deeper into the issue or create a PR. The changes can be seen here; https://github.com/nutgaard/graphql-kotlin/commit/4d8887878f372d521877801cc09549b952c125de
Issue Analytics
- State:
- Created 3 years ago
- Comments:8 (1 by maintainers)
Top GitHub Comments
I looked into updating
GraphQLClient
into a generic interface and while its possible to do it we would loose some of the existing Ktor customizability, i.e. current execute method signature acceptsHttpRequestBuilder.()
lambda which allows us to apply per request customization. If we move to generic interface then we would need to provide some generic mechanism to duplicate the same (or part of) functionality (e.g… maybe explicitly accept list of headers) that could then be applied in the specific implementations. I’m going to icebox generic client interface until we figure out a nice way to generically apply those customizations.In the meantime I just opened up the client (#811) so you could still extend it and create your custom client.
Change was released in
3.5.0