This content originally appeared on Level Up Coding - Medium and was authored by Akash

GraphQL has quickly become a favorite for modern web development, offering clients a flexible and efficient way to fetch exactly the data they need in a single request. However, when it comes to integrating GraphQL into a Spring Boot application, developers often find the process less intuitive compared to REST APIs — especially when it comes to making GraphQL queries in a declarative manner.
To solve this problem, I created GraphFeign, a library that enables you to call GraphQL APIs just like you would with Feign Client in a RESTful application. In this article, I’ll walk you through how to set up and use GraphFeign in a Spring Boot application, allowing you to make GraphQL requests easily and declaratively.
Prerequisites
Before diving into the implementation, ensure that you have the following in place:
- A Spring Boot project (we’ll be using Maven here).
- An understanding of how GraphQL works and how it differs from REST APIs.
Adding the GraphFeign Dependency
First, add the GraphFeign dependency to your pom.xml file. This is a straightforward Maven dependency.
<dependency>
<groupId>com.skycstech.graphclient</groupId>
<artifactId>graphclient-core</artifactId>
<version>0.0.1</version>
</dependency>
For the latest version, head over to the GitHub repository where you can get the most up-to-date code and documentation.
—
Configuring the GraphFeign Client
The core idea behind GraphFeign is to provide a declarative way to interact with a GraphQL API, similar to how you would interact with a REST API using Feign Client. Let’s walk through the configuration steps.
Step 1: Enable GraphFeign in Your Application
Start by enabling GraphFeign in your Spring Boot application. This is done by using the @EnableGraphFeignClientsannotation in your main application class. This annotation will trigger the necessary configuration for GraphFeign to start working.
@EnableGraphFeignClients
@SpringBootApplication
public class GraphFeignApplication {
public static void main(String[] args) {
SpringApplication.run(GraphFeignApplication.class, args);
}
}
Step 2: Define the GraphQL Client Interface
The next step is to define an interface that acts as the client for your GraphQL API. This is where the magic of GraphFeign happens. With just a few annotations, you can map methods to GraphQL queries and mutations.
@GraphFeignClient(name = "iGraphFeignClient",
url = "https://localhost:4351/graphql",
configuration = GQLClientConfiguration.class)
public interface IGraphFeignClient {
@GraphFeignRequest(documentName = "FetchBookByAuthorIDQuery", retrievePath = "books")
List<Book> getBooksByAuthorID(@GraphFeignVariable("request") Long bookAuthorID) throws GraphFeignException;
@GraphFeignRequest(documentName = "FetchBookByIDQuery", retrievePath = "book")
Book getBookByID(@GraphFeignVariable("request") Long bookId) throws GraphFeignException;
}
Here’s a quick breakdown of the annotations and their roles:
- @GraphFeignClient: Marks this interface as a GraphFeign client, pointing to the GraphQL endpoint URL. You can also specify a custom configuration class if needed.
- @GraphFeignRequest: Tells GraphFeign which GraphQL document to execute (via the documentName), and the path to retrieve data from in the response (via retrievePath).
- @GraphFeignVariable: Maps method parameters to GraphQL variables.
Example GraphQL Query Document:
Here’s an example of what the actual GraphQL query document might look like for FetchBookByAuthorIDQuery:
query FetchBookByAuthorID($request: ID!) {
books(bookAuthorID: $request) {
id
title
author
}
}
Step 3: Optional Custom Configuration
In some cases, you might want to customize the headers, interceptors, or the source from which the GraphQL documents are loaded. You can achieve this by implementing a custom configuration class.
public class GQLClientConfiguration implements GraphFeignClientConfiguration {
@Override
public Consumer<HttpHeaders> headersConsumer(Method method) {
return headers -> {
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
};
}
// Optional: Configure interceptors or custom document sources
/*
@Override
public Consumer<List<GraphQlClientInterceptor>> interceptorsConsumer(Method method) {
return interceptors -> {
// Add interceptors if necessary
};
}
@Override
public DocumentSource documentSource(Method method) {
return null; // You can provide a custom document source
}
*/
}
In this configuration class:
- headersConsumer: Adds headers like Content-Type: application/json to every request.
- interceptorsConsumer: Optionally allows you to add custom interceptors (for logging, retries, etc.).
- documentSource: Allows you to specify a custom source for loading GraphQL documents if needed. (Default DocumementSource path is resource/graphql-documents/)
Step 4: Using the Client in Your Service
Once you’ve defined the client interface and configured it, you can start using it in your service classes. Spring will automatically inject the GraphFeign client.
@Slf4j
@Service
@RequiredArgsConstructor
public class GraphFeignService {
@Resource // added this to avoid IDE error - Spring could resolve the bean without this at Runtime.
private final IGraphFeignClient graphFeignClient;
public List<Book> getBooksByAuthorID(Long bookAuthorID) {
try {
return graphFeignClient.getBooksByAuthorID(bookAuthorID);
} catch (GraphFeignException e) {
log.error("Error occurred while calling GraphQL API", e);
}
return Collections.emptyList();
}
}
Here, the GraphFeignService class calls the getBooksByAuthorID method from the IGraphFeignClient interface. If an error occurs, it’s caught and logged.
—
Advanced Features of GraphFeign
GraphFeign also supports more advanced use cases. Here are some additional features you can take advantage of:
1. Handling Multiple Operations in a Single Document
If your GraphQL document contains multiple operations, you can specify the operation name explicitly.
@GraphFeignRequest(documentName = "FetchBookByAuthorIDQuery",
operationName = "SomeOperationName",
retrievePath = "books")
List<Book> getBooksByAuthorID(@GraphFeignVariable("request") Long bookAuthorID) throws GraphFeignException;
2. Dynamically Loading GraphQL Queries
You can also pass the GraphQL query document dynamically, either by generating the query in the application or loading it from a source.
@GraphFeignRequest(retrievePath = "books")
List<Book> getBooksByAuthorID(@GraphFeignDocument String document,
@GraphFeignVariable("request") Long bookAuthorID) throws GraphFeignException;
Alternatively, you can load queries directly from a file or resource:
@GraphFeignRequest(retrievePath = "books")
List<Book> getBooksByAuthorID(@GraphFeignDocument(documentName = true) String document,
@GraphFeignVariable("request") Long bookAuthorID) throws GraphFeignException;
3. Using ClientGraphQlResponse for Fine-Grained Control
For more advanced use cases, you might want to receive the raw GraphQL response instead of just the data. You can use ClientGraphQlResponse to have more control over the response.
@GraphFeignRequest(documentName = "FetchBookByAuthorIDQuery")
Mono<ClientGraphQlResponse> getBooksByAuthorID(@GraphFeignVariable("request") Long bookAuthorID) throws GraphFeignException;
4. Subscription Requests
GraphFeign supports GraphQL subscriptions, which allow you to listen for real-time updates. This is particularly useful for applications that need live updates, such as chat applications or live feeds.
@GraphFeignRequest(documentName = "FetchBookByIDQuery",
retrievePath = "book",
isSubscription = true)
Flux<Book> getBookByID(@GraphFeignVariable("request") Long bookId) throws GraphFeignException;
5. Passing Variables and Headers
GraphQL queries often require variables, and you can pass these either through method parameters or headers.
@GraphFeignRequest(documentName = "FetchBookByIDQuery",
retrievePath = "book")
Book getBookByID(@GraphFeignHeader("Authorization") String authToken,
@GraphFeignVariable("request") Long bookId) throws GraphFeignException;
You can also pass variables as a map:
@GraphFeignRequest(documentName = "FetchBookByIDQuery",
retrievePath = "book")
Book getBookByID(@GraphFeignHeader("Authorization") String authToken,
Map<String, Object> variables) throws GraphFeignException;
—
Custom Configuration with Application Properties
In addition to programmatically configuring your GraphFeign client, you can control several important behaviors through application properties. This includes disabling SSL validation, adjusting logging levels, and masking sensitive headers.
Add the following properties to your application.yml or application.properties file to configure these options:
Example Configuration:
graph-feign:
client:
# Disable SSL certificate validation (useful for development environments)
disable-ssl-validation: true
# Set the logger level for GraphFeign requests and responses
loggerLevel: NONE # Options: NONE, BASIC, HEADERS, FULL
# Mask sensitive headers from the logs to avoid logging sensitive information
sensitiveHeaders:
- Authorization
- Cookie
Property Details:
- disable-ssl-validation: Disables SSL validation for the GraphQL endpoint. Set this to true if you’re using self-signed certificates or during development. Caution: This is not recommended for production environments due to security risks.
- loggerLevel: Controls the level of logging for GraphQL requests and responses. Available levels are:
-NONE: No logging (default).
-BASIC: Logs request method and URL.
-HEADERS: Logs headers.
-FULL: Logs request and response body content (useful for debugging but can log sensitive data). - sensitiveHeaders: Specifies a list of headers that should be masked in the logs to protect sensitive data like authentication tokens or cookies. Note: This only mask 70% of the given value.
—
Providing a GraphFeignCustomizer Bean
To further customize the GraphFeign client beyond the default configuration, you can provide a GraphFeignCustomizer bean. This allows you to customize various aspects of the WebClient, Document Source, GraphFeignLogger, CodecConfigurer, and ObjectMapper.
For example, you can customize the WebClient to add custom interceptors, configure timeouts, or modify the underlying HTTP client.
Example GraphFeignCustomizer:
@Bean
public GraphFeignCustomizer graphFeignCustomizer() {
return new GraphFeignCustomizer()
.setWebClient(WebClient.builder().build());
}
—
Conclusion
GraphFeign simplifies the process of making GraphQL requests in a Spring Boot application by providing a declarative, Feign-like client for interacting with GraphQL APIs. By combining the power of Spring Boot and WebClient with the flexibility of GraphQL, GraphFeign allows you to handle all the nuances of GraphQL queries and mutations without the boilerplate.
Ready to give it a try? Check out the GraphFeign GitHub repository for the source code.
GraphFeign: A Feign-Like Client for GraphQL Queries and Mutations was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Level Up Coding - Medium and was authored by Akash

Akash | Sciencx (2025-01-07T17:30:43+00:00) GraphFeign: A Feign-Like Client for GraphQL Queries and Mutations. Retrieved from https://www.scien.cx/2025/01/07/graphfeign-a-feign-like-client-for-graphql-queries-and-mutations/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.