001package org.hl7.fhir.r4.hapi.rest.server; 002 003import ca.uhn.fhir.context.ConfigurationException; 004import ca.uhn.fhir.context.FhirContext; 005import ca.uhn.fhir.context.FhirVersionEnum; 006import ca.uhn.fhir.rest.annotation.GraphQL; 007import ca.uhn.fhir.rest.annotation.GraphQLQuery; 008import ca.uhn.fhir.rest.annotation.IdParam; 009import ca.uhn.fhir.rest.annotation.Initialize; 010import ca.uhn.fhir.rest.server.RestfulServer; 011import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; 012import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; 013import org.hl7.fhir.instance.model.api.IIdType; 014import org.hl7.fhir.r4.context.IWorkerContext; 015import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport; 016import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext; 017import org.hl7.fhir.r4.hapi.ctx.IValidationSupport; 018import org.hl7.fhir.r4.model.Resource; 019import org.hl7.fhir.r4.utils.GraphQLEngine; 020import org.hl7.fhir.utilities.graphql.ObjectValue; 021import org.hl7.fhir.utilities.graphql.Parser; 022import org.slf4j.Logger; 023import org.slf4j.LoggerFactory; 024 025public class GraphQLProvider { 026 private final IWorkerContext myWorkerContext; 027 private Logger ourLog = LoggerFactory.getLogger(GraphQLProvider.class); 028 private GraphQLEngine.IGraphQLStorageServices myStorageServices; 029 030 /** 031 * Constructor which uses a default context and validation support object 032 * 033 * @param theStorageServices The storage services (this object will be used to retrieve various resources as required by the GraphQL engine) 034 */ 035 public GraphQLProvider(GraphQLEngine.IGraphQLStorageServices theStorageServices) { 036 this(FhirContext.forR4(), new DefaultProfileValidationSupport(), theStorageServices); 037 } 038 039 /** 040 * Constructor which uses the given worker context 041 * 042 * @param theFhirContext The HAPI FHIR Context object 043 * @param theValidationSupport The HAPI Validation Support object 044 * @param theStorageServices The storage services (this object will be used to retrieve various resources as required by the GraphQL engine) 045 */ 046 public GraphQLProvider(FhirContext theFhirContext, IValidationSupport theValidationSupport, GraphQLEngine.IGraphQLStorageServices theStorageServices) { 047 myWorkerContext = new HapiWorkerContext(theFhirContext, theValidationSupport); 048 myStorageServices = theStorageServices; 049 } 050 051 @GraphQL 052 public String graphql(ServletRequestDetails theRequestDetails, @IdParam IIdType theId, @GraphQLQuery String theQuery) { 053 054 GraphQLEngine engine = new GraphQLEngine(myWorkerContext); 055 engine.setServices(myStorageServices); 056 try { 057 engine.setGraphQL(Parser.parse(theQuery)); 058 } catch (Exception theE) { 059 throw new InvalidRequestException("Unable to parse GraphQL Expression: " + theE.toString()); 060 } 061 062 try { 063 064 if (theId != null) { 065 Resource focus = myStorageServices.lookup(theRequestDetails, theId.getResourceType(), theId.getIdPart()); 066 engine.setFocus(focus); 067 } 068 engine.execute(); 069 070 StringBuilder outputBuilder = new StringBuilder(); 071 ObjectValue output = engine.getOutput(); 072 output.write(outputBuilder, 0, "\n"); 073 074 return outputBuilder.toString(); 075 076 } catch (Exception theE) { 077 throw new InvalidRequestException("Unable to execute GraphQL Expression: " + theE.toString()); 078 } 079 } 080 081 @Initialize 082 public void initialize(RestfulServer theServer) { 083 ourLog.trace("Initializing GraphQL provider"); 084 if (theServer.getFhirContext().getVersion().getVersion() != FhirVersionEnum.R4) { 085 throw new ConfigurationException("Can not use " + getClass().getName() + " provider on server with FHIR " + theServer.getFhirContext().getVersion().getVersion().name() + " context"); 086 } 087 } 088 089 090} 091