001/* 002 * #%L 003 * HAPI FHIR - Server Framework 004 * %% 005 * Copyright (C) 2014 - 2024 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.rest.server.method; 021 022import ca.uhn.fhir.context.ConfigurationException; 023import ca.uhn.fhir.i18n.Msg; 024import ca.uhn.fhir.rest.annotation.Count; 025import ca.uhn.fhir.rest.api.Constants; 026import ca.uhn.fhir.rest.api.server.RequestDetails; 027import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 028import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; 029import com.fasterxml.jackson.databind.JsonNode; 030import com.fasterxml.jackson.databind.ObjectMapper; 031import org.apache.commons.io.IOUtils; 032 033import java.io.IOException; 034import java.io.Reader; 035import java.lang.reflect.Method; 036import java.util.Collection; 037 038import static ca.uhn.fhir.rest.api.Constants.CT_GRAPHQL; 039import static ca.uhn.fhir.rest.api.Constants.CT_JSON; 040import static ca.uhn.fhir.rest.server.method.ResourceParameter.createRequestReader; 041import static org.apache.commons.lang3.StringUtils.defaultString; 042import static org.apache.commons.lang3.StringUtils.trim; 043 044public class GraphQLQueryBodyParameter implements IParameter { 045 046 private Class<?> myType; 047 048 @Override 049 public Object translateQueryParametersIntoServerArgument( 050 RequestDetails theRequest, BaseMethodBinding theMethodBinding) 051 throws InternalErrorException, InvalidRequestException { 052 String ctValue = defaultString(theRequest.getHeader(Constants.HEADER_CONTENT_TYPE)); 053 Reader requestReader = createRequestReader(theRequest); 054 055 // Trim off "; charset=FOO" from the content-type header 056 int semicolonIdx = ctValue.indexOf(';'); 057 if (semicolonIdx != -1) { 058 ctValue = ctValue.substring(0, semicolonIdx); 059 } 060 ctValue = trim(ctValue); 061 062 if (CT_JSON.equals(ctValue)) { 063 try { 064 ObjectMapper mapper = new ObjectMapper(); 065 JsonNode jsonNode = mapper.readTree(requestReader); 066 if (jsonNode != null && jsonNode.get("query") != null) { 067 return jsonNode.get("query").asText(); 068 } 069 } catch (IOException e) { 070 throw new InternalErrorException(Msg.code(356) + e); 071 } 072 } 073 074 if (CT_GRAPHQL.equals(ctValue)) { 075 try { 076 return IOUtils.toString(requestReader); 077 } catch (IOException e) { 078 throw new InternalErrorException(Msg.code(357) + e); 079 } 080 } 081 082 return null; 083 } 084 085 @Override 086 public void initializeTypes( 087 Method theMethod, 088 Class<? extends Collection<?>> theOuterCollectionType, 089 Class<? extends Collection<?>> theInnerCollectionType, 090 Class<?> theParameterType) { 091 if (theOuterCollectionType != null) { 092 throw new ConfigurationException(Msg.code(358) + "Method '" + theMethod.getName() + "' in type '" 093 + theMethod.getDeclaringClass().getCanonicalName() + "' is annotated with @" + Count.class.getName() 094 + " but can not be of collection type"); 095 } 096 if (!String.class.equals(theParameterType)) { 097 throw new ConfigurationException(Msg.code(359) + "Method '" + theMethod.getName() + "' in type '" 098 + theMethod.getDeclaringClass().getCanonicalName() + "' is annotated with @" + Count.class.getName() 099 + " but type '" + theParameterType + "' is an invalid type, must be one of Integer or IntegerType"); 100 } 101 myType = theParameterType; 102 } 103}