Developing GraphQL API with Netflix DGS Framework(Part-IV)
This is the fourth post of the series. For the first three posts of this series you can follow the given links part-I, part-II, part-III
In this post, I will explain about the Named queries
and how to do File uploading
in GraphQL using Netflix DGS Framework
Named Queries and Parameter placeholders
In our previous posts, we have used GraphQL queries and mutations, like below.
query {
employee(id :1){
first_name
last_name
}
}
Code language: Java (java)
mutation {
createEmployee (employee :{first_name: "Alex" ,last_name : "Peak" ,gender : M ,deptId:1}) {
id
first_name
}
}
Code language: Java (java)
Above style has 2 problems.
Suppose we want to have 2 queries, one with Employee and Department information included and another with only Employee information.
Since query or mutation has no name, we need to look at the response fields to understand the query.
Second problem is parameters are hard coded, if we want to use the queries in GraphQL client , passing params based on the user input will be tedious.We have
Gra[hQLaddresses these problems with Named Queries and Paramter place holders.
For every query, we can write name like below. Observe that after query and mutation key word, I have written some meaningful string to identify the query and mutations.
Named queries also helps in debugging and server-side logging reasons, it’s useful to give your queries meaningful names. That way, when you see something wrong going on either in your network logs or your GraphQL server , you can easily find that query in your codebase by name instead of trying to decipher the contents. Think of it like a function name in your favourite programming language
query GetEmployee{
employee(id :1){
first_name
last_name
}
}
query GetEmployeeWithDept{
employee(id :1){
first_name
last_name
department {
dept_name
}
}
}
mutation createEmployee{
createEmployee (employee :{first_name: "Alex" ,last_name : "Peak" ,gender : M ,deptId:1}) {
id
first_name
}
}
Code language: JSON / JSON with Comments (json)
Parameter placeholders
Second problem is parameters are hard coded in above queries, if we want to use the queries in GraphQL client , passing parameters based on the user input will be tedious.We have to build entire query string based on the user input.
GraphQL addresses this problem with parameter placeholders.
Below, you can observe that placeholders are defined with $ sign.
After query name we write placeholder parameter and its type
GetEmployee ($id : Int)
,then pass the placeholder to actual query
employee(id :$id)
query GetEmployee ($id : Int){
employee(id :$id){
first_name
last_name
}
}
mutation createEmployee ($employee : SubmittedEmployee){
createEmployee (employee : $employee) {
id
first_name
}
}
Code language: JSON / JSON with Comments (json)
Let’s test the above queries with Altair GraphQL client. You can observe that variables are passed from variables section
In this blog post , let’s see how to upload a file to GraphQL server.
File Uploading with GraphQL
In GraphQL, file upload operation treated as mutation request from a client to GraphQL server.
The Netflix DGS framework supports the Upload
scalar with which you can specify files in your mutation query as a MultipartFile
. When you send a multipart request for file upload, the framework processes each part and assembles the final GraphQL query that it hands to your data fetcher for further processing.
Let’s add the file uploading feature in our api
First we need to declare Upload
scalar and then define mutation operation.
scalar Upload
type Mutation {
uploadEmployeePhoto(emp_id: Int! ,inputFile : Upload!): String
}
Code language: JSON / JSON with Comments (json)
Now we need to implement the uploadEmployeePhoto
method
@DgsComponent
public class EmployeePhotoUploadDataFetcher {
@DgsMutation
public String uploadEmployeePhoto(@InputArgument(name="emp_id") Integer empId, @InputArgument MultipartFile inputFile) throws IOException {
System.out.println("empId :"+empId);
Path uploadDir = Paths.get("uploaded-images");
if (!Files.exists(uploadDir)) {
Files.createDirectories(uploadDir);
}
String fileName = empId+"-"+inputFile.getOriginalFilename();
Path newFile = uploadDir.resolve(fileName);
try (OutputStream outputStream = Files.newOutputStream(newFile)) {
outputStream.write(inputFile.getBytes());
}
return newFile.toUri().toString();
}
}
Code language: Java (java)
Now let’s test the function with Altair GraphQL client. Since the method is expecting file input, select the Add files
option from the bottom of the screen, set inputFile
as the variable name ( you need to set variable name as per method definition) and use select file link to select the file to upload.
Enter empId value in the variables section
Unit testing GraphQL file upload
We use the MockMultipartFile
class to simulate the MultipartFile
object
@SpringBootTest(classes = { DgsAutoConfiguration.class, DateScalar.class, EmployeePhotoUploadDataFetcher.class })
public class EmployeePhotoUploadDataFetcherTest {
@Autowired
DgsQueryExecutor dgsQueryExecutor;
@Autowired
EmployeePhotoUploadDataFetcher empPhotoUploader;
@Test
public void test_uploadEmployeePhoto() throws IOException {
MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt", "text/plain",
"Spring Framework".getBytes());
String url = empPhotoUploader.uploadEmployeePhoto(1, multipartFile);
assertThat(url).contains("test");
}
}
Code language: Java (java)
You can download source code for this blog post from GitHub
Other posts in this series