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

mutation placeholder

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

GraphQL File upload

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

Similar Posts