Invoking GraphQL APIs

API developed using GraphQL is normally provided a convenient UI Tools that can be used to test the API calls. there are various tools that can be used to build this as mentioned here.

You can easily enter the payload, Query Variables and HTTP Headers to invoke the API calls.

ref : https://anilist.co/graphiql

ref :

  • https://docs-search.hoteltrader.com/gui
  • https://hotel-trader.stoplight.io/docs/pull-api/ZG9jOjE0Njk0OTU0-overview

Also, you can use the Docs and Schema to see how is the API Structured before calling it.

Anyway, same calls can be done trough curl or any HTTP client (eg : Postman / Insomnia / Direct Java HTTP Client code ). You can use debug mode (F12) in the browser to see how is the request goes to back-end.

curl :

curl 'https://docs-search.hoteltrader.com/graphql' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Connection: keep-alive' -H 'DNT: 1' -H 'Origin: https://docs-search.hoteltrader.com' --data-binary '{"query":"# Write your query or mutation here\nquery getPropertiesByIds($SearchCriteriaByIds: SearchCriteriaByIdsInput) {\n  getPropertiesByIds(searchCriteriaByIds: $SearchCriteriaByIds) {\n  properties {\n      propertyId\n      propertyName\n      occupancies {\n        occupancyRefId\n        checkInDate\n        checkOutDate\n        numberOfAdults\n        numberOfChildren\n        childrenAges\n      }\n      rooms {\n        occupancyRefId\n        htIdentifier\n        roomName\n        shortDescription\n        longDescription\n       \n        rateInfo {\n          bar\n          binding\n          commissionable\n          commissionAmount\n          currency\n          netPrice\n          tax\n          grossPrice\n          payAtProperty\n          dailyPrice\n          dailyTax\n         \n          taxInfo {\n            payAtBooking {\n              date\n              name\n              description\n              value\n            }\n            payAtProperty {\n              date\n              name\n              description\n              value\n            }\n          }\n        }\n        mealplanOptions{\n          breakfastIncluded\n          lunchIncluded\n          dinnerIncluded\n          allInclusive\n          mealplanDescription\n        }\n        rateplanTag\n        refundable\n        cancellationPolicies {\n          startWindowTime\n          endWindowTime\n          cancellationCharge\n          timeZone\n        }\n      }\n\t\t\tshortDescription\n\t\t\tlongDescription\n      city\n      latitude\n      longitude\n      starRating\n      hotelImageUrl\n    }\n  }\n}","variables":{"SearchCriteriaByIds":{"propertyIds":[134388],"occupancies":[{"checkInDate":"2022-06-01","checkOutDate":"2022-06-02","numberOfAdults":2,"numberOfChildren":0,"childrenAges":""}]}}}' --compressed

Postman :

Java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import com.fasterxml.jackson.databind.ObjectMapper;

public class HotelTradeSearchTest {
	
	public static void main(String[] args) throws IOException {

		sendPOST();
		System.out.println("POST DONE");
	}

	private static void sendPOST() throws IOException {
		URL obj = new URL("https://docs-search.hoteltrader.com/graphql");
		HttpURLConnection con = (HttpURLConnection) obj.openConnection();
		con.setRequestMethod("POST");
		con.setRequestProperty("Content-Type", "application/json");

		// For POST only - START
		con.setDoOutput(true);
		OutputStream os = con.getOutputStream();
		os.write(
				("{\n"
				+ "\n"
				+ "    \"operationName\":\"getPropertiesByCity\",\n"
				+ "    \"variables\":{\n"
				+ "        \"searchCriteriaByCity\":{\n"
				+ "            \"city\":\"New York, New York, United States Of America\",\n"
				+ "            \"occupancies\":[\n"
				+ "                {\n"
				+ "                    \"checkInDate\":\"2022-06-01\",\n"
				+ "                    \"checkOutDate\":\"2022-06-02\",\n"
				+ "                    \"numberOfAdults\":2,\n"
				+ "                    \"numberOfChildren\":0,\n"
				+ "                    \"childrenAges\":\"\"\n"
				+ "                }\n"
				+ "            ]\n"
				+ "        }\n"
				+ "    },\n"
				+ "    \"query\":\"query getPropertiesByCity($searchCriteriaByCity: SearchCriteriaByCityInput) {\\n getPropertiesByCity(searchCriteriaByCity: $searchCriteriaByCity) {\\n properties {\\n propertyId\\n propertyName\\n occupancies {\\n occupancyRefId\\n checkInDate\\n checkOutDate\\n numberOfAdults\\n numberOfChildren\\n childrenAges\\n }\\n rooms {\\n occupancyRefId\\n htIdentifier\\n roomName\\n shortDescription\\n longDescription\\n rateInfo {\\n bar\\n binding\\n commissionable\\n commissionAmount\\n currency\\n netPrice\\n tax\\n grossPrice\\n payAtProperty\\n dailyPrice\\n dailyTax\\n taxInfo {\\n payAtBooking {\\n date\\n name\\n description\\n value\\n }\\n payAtProperty {\\n date\\n name\\n description\\n value\\n }\\n }\\n }\\n mealplanOptions {\\n breakfastIncluded\\n lunchIncluded\\n dinnerIncluded\\n allInclusive\\n mealplanDescription\\n }\\n rateplanTag\\n refundable\\n cancellationPolicies {\\n startWindowTime\\n endWindowTime\\n cancellationCharge\\n timeZone\\n }\\n }\\n shortDescription\\n longDescription\\n city\\n latitude\\n longitude\\n starRating\\n hotelImageUrl\\n }\\n }\\n}\\n\"\n"
				+ "\n"
				+ "}").getBytes()
				);
		os.flush();
		os.close();
		// For POST only - END

		int responseCode = con.getResponseCode();
		System.out.println("POST Response Code :: " + responseCode);

		if (responseCode == HttpURLConnection.HTTP_OK) { // success
			BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
			String inputLine;
			StringBuffer response = new StringBuffer();

			while ((inputLine = in.readLine()) != null) {
				response.append(inputLine);
			}
			in.close();

			ObjectMapper mapper = new ObjectMapper();
			System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(mapper.readTree(response.toString())));
			
		} else {
			System.out.println("POST request not worked");
		}
	}
}

Maven dependencies:

		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-core</artifactId>
			<version>2.11.2</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.11.2</version>
		</dependency>

References :

  • https://www.graphql-java.com/
  • https://www.baeldung.com/spring-graphql
  • https://www.howtographql.com/graphql-java/0-introduction/
  • https://developer.okta.com/blog/2020/01/31/java-graphql
  • https://github.com/graphql-java/graphql-java
  • https://github.com/graphql-java/tutorials/tree/master/book-details
  • https://www.programcreek.com/java-api-examples/?api=graphql.schema.idl.RuntimeWiring
  • https://www.tabnine.com/code/java/classes/graphql.schema.idl.RuntimeWiring
  • https://search.maven.org/artifact/com.graphql-java/graphql-java/16.2/jar
  • http://www.java2s.com/example/jar/g/download-graphqljava40jar-file.html
  • https://graphql.org/code/#generic-tools

#apis, #graphql, #java, #rest

SOAP UI Mock Service Runner


sudo bash /{{SoapUI-Root}}/bin/mockservicerunner.sh -Dsoapui.mock.connector.headerBufferSize=16000 {{url-or-path-to-project-xml}}

Example :

  • sudo bash /apps/soapUI/SoapUI-5.4.0/bin/mockservicerunner.sh -Dsoapui.mock.connector.headerBufferSize=16000 https://mock.awshost.io/soapUI/Projects/mock-xyz-soapui-project.xml &
  • sudo bash /home/namal/Fun/soapui/SoapUI-5.6.0/bin/mockservicerunner.sh -Dsoapui.mock.connector.headerBufferSize=16000 /home/namal/Fun/soapui/test-mock/Project-1-soapui-project.xml

Match response based on request body

def requestBody = mockRequest.getRequestContent()
log.info "Request body: " + requestBody

if( requestBody.contains("reschedule") ){
return "Reschedule POST res"
}
else if( requestBody.contains("cause") ){
return "Cancel Response"
}else if( requestBody.contains("amendendusertype") ){
return "Ammend-EndUser-POST"
}

Calling TestSuit within MockService

OnRequest Script

import com.eviware.soapui.support.types.StringToStringMap 
import java.net.URL
import groovy.json.JsonSlurper

def authtoken = ""
def post = new URL("https://keycloak.awshost.io/auth/realms/cossmos/protocol/openid-connect/token").openConnection()
def message = 'grant_type=password&client_id=xyzClient&username=xyz&password=123456&client_secret=dsa213-4gfd-5645fds42423-324das'

post.setRequestMethod("POST")
post.setDoOutput(true)
post.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
post.getOutputStream().write(message.getBytes("UTF-8"))

def postRC = post.getResponseCode()
if(postRC.equals(200)) {
	def resp = post.getInputStream().getText()
	def json = new JsonSlurper().parseText(resp)
	authtoken = json.'access_token'
	log.info("Call back authToken retrieved!");
}else{
	log.info("Call back authToken not retrieved!")
}

context.setProperty("authtoken","bearer " + authtoken)

def callbackEp = mockRequest.getRequestHeaders().get("callback-ep-uri").get(0).toString()
context.setProperty("callback-ep-uri",callbackEp)

AfterRequest Script

import com.eviware.soapui.support.GroovyUtils
import com.eviware.soapui.support.types.StringToObjectMap
import com.eviware.soapui.impl.wsdl.teststeps.RestTestRequestStep
import com.eviware.soapui.support.types.StringToStringMap 

def groovyUtils = new GroovyUtils( context )
def headers = new StringToStringMap()

if(mockResult != null){

	def requestContent=mockResult.getMockRequest().requestContent;
	def requestBody = new groovy.json.JsonSlurper().parseText(requestContent)
	
	def map = new StringToObjectMap()
	def authtoken = context.getProperty("authtoken")
	def callbackEndpoint = context.getProperty("callback-ep-uri")

	def testsuite = context.mockService.project.getTestSuiteByName("MagnifyDiagnosticTestsuite")
	def testcaseName = null;
	def actualExtId = null;

	if(requestBody.cause != null){
		testcaseName = "AppointmentCancel"
	}else if(requestBody.externalId.contains("reschedule")){
		testcaseName = "ApppointmentReschedule"
	}else{
		testcaseName = "AppointmentCallbackAsyncMessages"
	}

	if(requestBody.externalId.contains("-::") ){
		actualExtId = requestBody.externalId.split('-::')
	}
		
	def testcase = testsuite.getTestCaseByName(testcaseName)

	if(actualExtId != null){
		testcase.setPropertyValue( "externalId", actualExtId[0] )
	}else{
		testcase.setPropertyValue( "externalId", requestBody.externalId )
	}

	headers.put("Authorization",authtoken)
	headers.put("Content-Type","application/json")
	headers.put("NBN-ConversationID","unique-identifier")
	headers.put("NBN-APIVersion","test-version")
	headers.put("NBN-RSPSecurityToken","securityTokenValue")
	headers.put("NBN-TransactionID","transaction-id")

	def teststep = testcase.getTestStepsOfType(RestTestRequestStep.class)
	teststep.eachWithIndex(){ step, index -> 
		teststep.get(index).testRequest.setEndpoint(callbackEndpoint)
		teststep.get(index).testRequest.setRequestHeaders(headers)
	}

	testcase.run(map, true) //true here means call asynchronously i.e. dont wait to the TestCase to finish first
}

#mock, #rest, #soapui