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