GraphQL in simple terms is a querying language for your API that lets the client i.e UI query on the data fetched by the API.
GraphQL is not tied to any database it is instead linked to your API data, which API might have fetched from the database. Thus Graphql could easily be integrated with your existing API service. If you still have doubts in understanding what is GraphQL then the last section of this post would clear it.
Below are some of the advantages of using GraphQL API
- Ask for what you need, get exactly that: Send a GraphQL query to your API and get exactly which fields you need, nothing more and nothing less, unlike REST where you would give all the fields.
- Get many resources in a single request: Unlike REST APIs which requires loading from multiple URLs, GraphQL APIs get all the data your app needs in a single request. Thus apps using GraphQL can be quicker even on slow mobile network connections.
- Evolve your API without versions: Add new fields and types to your GraphQL API without impacting existing queries.
All that being said let’s get into the coding aspect. In this post, you will see how you can set up GraphQL in a Springboot project. For demonstration, we would be creating a spring boot application that gives users details.
Step 1 : Schema & Type
In your spring boot project create a GraphQL file in the resource directory. Define an entity or type called “User” and add all the fields that the API could possibly send.
Next, provide a query. Queries in GraphQL are like endpoints in REST API.
In our example, we would write two GraphQL queries one would fetch all users while other would fetch a specific user.
schema.graphql
type User {
name: String
address: String
id: String
age: Int
}
type Query {
allUsers: [User]
user(id: String): User
}
schema {
query: Query
}
Step 2 : Datafetcher & Service
Datafetchers job is to get the data from the application and send it to GraphQL service which then maps datafetchers classes with the queries defined in the schema.
Each query is linked to a particular dataFetcher class for ex in our demo “allUsers” query is linked to AllUsersDataFetcher class and “user” query is linked to UserDataFetcher class.
GraphQL service exposes one public function “getGraphQL()” that is used by the controllers class to execute the POST request query sent by UI and returns the query result.
@Service
public class GraphqlService {
@Value("classpath:users.graphql")
Resource resource;
@Autowired
AllUsersDataFetcher allUsersDataFetcher;
@Autowired
UserDataFetcher userDataFetcher;
private GraphQL graphQL;
@PostConstruct
private void GraphqlService() throws IOException {
File schemaFile = resource.getFile();
TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(schemaFile);
RuntimeWiring wiring = buildRuntimeWiring();
GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(typeRegistry, wiring);
graphQL = GraphQL.<em>newGraphQL</em>(schema).build();
}
private RuntimeWiring buildRuntimeWiring() {
return RuntimeWiring.<em>newRuntimeWiring</em>()
.type("Query", typeWiring -> typeWiring
.dataFetcher("allUsers", allUsersDataFetcher)
.dataFetcher("user", userDataFetcher)
)
.build();
}
public GraphQL getGraphQL() {
return graphQL;
}
}
@Component
public class UserDataFetcher implements DataFetcher {
@Override
public Object get(DataFetchingEnvironment environment) {
Users u1 = new Users();
Users u2 = new Users();
// Query the database and set the users object
// For this example lets hardcode the output
u1.setAddress("at home");
u1.setAge(32);
u1.setId("1");
u1.setName("Duck");
u2.setAddress("at home");
u2.setAge(12);
u2.setId("2");
u2.setName("Bear");
String id = environment.getArgument("id");
return (id == "1") ? u1 : u2;
}
@Component
public class AllUsersDataFetcher implements DataFetcher {
@Override
public Object get(DataFetchingEnvironment environment) {
List<Users> users = new ArrayList<>();
// Query the database and set the users object
// For this example lets hardcode the output
Users u1 = new Users();
Users u2 = new Users();
u1.setAddress("at home");
u1.setAge(32);
u1.setId("1");
u1.setName("Duck");
u2.setAddress("at home");
u2.setAge(12);
u2.setId("2");
u2.setName("Bear");
users.add(u1);
users.add(u2);
return users;
}
}
Step 3 : Endpoint
One endpoint for your entire project, how fascinating. Yes, there is just one endpoint for the entire application. You can execute all the queries against a single “/graphql” endpoint.
Note unlike REST API, GraphQL doesn’t support GET, DELETE or PUT request, it works on POST request only and beside you really don’t need them in GraphQL implementation. Since to GET or DELETE all that you would need to do is write a DELETE or GET query.
Below is Controller class that exposes “/graphql” endpoint, it receives Query as RequestBody which is then passed to GraphQL Service. Service then executes the query and return the query result.
@RestController
public class UsersController implements UsersControllerInterface {
@Autowired
GraphqlService graphqlService;
@PostMapping("/graphql")
@Override
public ResponseEntity<Object> getAllUsers(@RequestBody String query) {
ExecutionResult execute = graphqlService.getGraphQL().execute(query);
return new ResponseEntity<>(execute, HttpStatus.<em>OK</em>);
}
}
Step 4 : Execute Query
Make a simple POST request to the “graphql” endpoint and pass the query that you want to execute, along with fields that you would like to receive in return.
In the below screenshot you would see we are executing “allUsers” query and asking for name, age, and address field only and that is exactly what you get.
Thus avoiding over fetching of data and also the need to create a separate API in case of REST approach.
Generally in applications, you would see there are many API calls that are made upon the page load thus consuming more network and server resources.
With help of GraphQL implementation, you can minimize network and server resources consumption by combining all these initial API calls into a single call and achieve better performance.
In the below request we are executing both “allUsers” and “user” query in a single request and getting output together.
Hope this was helpful in shedding some light on GraphQL implementation.
As always you can find the source code for this project at my GitHub repo https://github.com/thatsrohitnaik/Springboot-GraphQL
Happy Coding !!