I've written this, it still requires a bit of work for dealing with errors correctly as it does not yet use the reply action codes correctly.
 

ClassComponent.Oauth.HL7HttpOperationPassThroughExtendsEnsLib.HL7.Operation.HTTPOperation
{
///Content-Type header of the payload
PropertyContentTypeAs%String[InitialExpression="x-application/hl7-v2+er7; charset=utf-8",Required];
PropertyOAuthClientApplicationNameAs%String(MAXLEN=64,MINLEN=1)[InitialExpression="SystemApplicationName",Required];
PropertyOAuthScopeAs%String(MAXLEN=1024);
ParameterADAPTER="EnsLib.HTTP.OutboundAdapter";
PropertyAdapterAsEnsLib.HTTP.OutboundAdapter;
///Default is don't need all the info off the response so just return the Status line
PropertyCondensedHTMLResponseAs%Boolean[InitialExpression=1,Required];
///JSON formatted string of parameters to be sent with the OAuth2 request
///e.g. {"ContentType":"x-application/hl7-v2+er7; charset=utf-8","OAuthClientApplicationName":"SystemApplicationName","OAuthScope":"OAuth","OAuthTokenSessionId":"SYSTOKENID"}
PropertyParamsAs%String(MAXLEN=500000);
PropertyOAuthTokenSessionIdAs%String[InitialExpression="SYSTOKENID",Required];
ParameterSETTINGS="ContentType:Basic,OAuthClientApplicationName:OAuth,OAuthScope:OAuth,OAuthTokenSessionId:OAuth, Params:OAuth";
MethodSendMessage(pMsgOutAsEnsLib.HL7.Message,OutputpMsgInAsEnsLib.HL7.Message,pExpectedSequenceNumberAs%String)As%Status
{
    $$$TRACE("Component.Oauth.HL7HttpOperationPassThrough:SendMessage")
   
    Set pMsgIn=$$$NULLOREF, tHttpRequest=##class(%Net.HttpRequest).%New(), tHttpRequest.WriteRawMode=1
    // Add these two lines after the first in SendMessage. Change the content type to your desired header.
    Set tSC = tHttpRequest.SetHeader("Content-Type", ..ContentType)
    s tHttpRequest.EntityBody=##class(%IO.StringStream).%New()
    s tHttpResponse =##class(%Net.HttpResponse).%New()
    set sc=tHttpRequest.EntityBody.Write(pMsgOut.RawContent)
    s tHttpRequest.Port=443
    s tHttpRequest.FollowRedirect=1
   
    $$$TRACE("Component.Oauth.HL7HttpOperationPassThrough:SendMessage Rawcontent " _ tHttpRequest.EntityBody.Size _ " " _ tHttpRequest.EntityBody.Read(1000))
    Set tSC = ..AddAccessToken(.tHttpRequest)
    Set sessionId=..%SessionId
   
    $$$TRACE("Component.Oauth.HL7HttpOperationPassThrough:AddAccessToken " _ tSC _ " " _ sessionId)
     
    Quit:$$$ISERR(tSC) tSC
    // Copy the rest of the SendMessage Method from the standard EnsLib.HL7.Operation.HTTPOperation
   // Set tMetaIOStream=##class(%IO.MetaCharacterStream).%New(tHttpRequest.EntityBody)
    //Set tSC=..OutputFramedToIOStream(tMetaIOStream,pMsgOut,..Separators,pExpectedSequenceNumber,1,..IOLogEntry) Quit:$$$ISERR(tSC) tSC
   
    // Initialize the EntityBody as a StringStream
    Set tHttpRequest.EntityBody = ##class(%IO.StringStream).%New()
    // Convert HL7 message to a properly formatted string with segment separators
    Set hl7Content = "",seg=""
    $$$TRACE(pMsgOut.SegCountGet())
    For segmentIndex = 1:1:pMsgOut.SegCountGet() {
        Set segment = pMsgOut.GetSegmentAt(segmentIndex)
        Set hl7Content = hl7Content _ segment.OutputToString() _ " "// Append segment and carriage return
        s seg=""_segment.OutputToString()_" "
       
        Set tSC = tHttpRequest.EntityBody.Write(seg) Quit:$$$ISERR(tSC)
    }
    //$$$TRACE("Formatted HL7 Content: " _ hl7Content)
    // Write the HL7 content to the EntityBody
    //Set tSC = tHttpRequest.EntityBody.Write(hl7Content)
    //If $$$ISERR(tSC) Quit tSC
    //$$$TRACE(tHttpRequest.EntityBody.Read(10000))
    //Set tSC = tHttpRequest.EntityBody.Write(hl7Content)
   
    Set tHttpRequest.ResponseStream=##class(%IO.StringStream).%New()
    $$$TRACE("Component.Oauth.HL7HttpOperationPassThrough:Authorization " _ tHttpRequest.Authorization _ " " _ sessionId)
   
    Set tHttpResponse = ##class(%Net.HttpResponse).%New()
    S send="POST"
    $$$TRACE("Sending to "_..Adapter.URL)
    s tSC = ..SendRequest(.tHttpResponse,send,tHttpRequest, .pResponse)
    //$$$TRACE(tHttpResponse.Data)
   
    // If response body is empty, write status info into stream
    If tHttpResponse.Data.Size = 0 && tHttpResponse.StatusCode >0 {
        Do tHttpResponse.Data.Write(tHttpResponse.StatusCode _ " " _ tHttpResponse.StatusLine)
    }
    #; Account for Adapter generating an error based on StatusCode
    If $$$ISERR(tSC),'$$$StatusEquals(tSC,$$$EnsErrHTTPStatus) Quit tSC
    If $IsObject(tHttpResponse.Data),tHttpResponse.Data.Size {
        $$$TRACE("Component.Oauth.HL7HttpOperationPassThrough:Reponse " _ tHttpResponse.StatusCode _ " " _ sessionId)
        //check framing....
        $$$TRACE("RESPONSE FRAME")
        $$$TRACE(tHttpResponse.Data.Read())
        do tHttpResponse.Data.Rewind()
        $$$TRACE(tHttpResponse.Data.Read())
        do tHttpResponse.Data.Rewind()
        set tHL7=tHttpResponse.Data.Read()
        Set tSC1=..%Parser.ParseFramedIOStream(tHttpResponse.Data,.pMsgIn,0,..IOLogEntry) Quit:$$$ISERR(tSC1) $$$ADDSC(tSC,tSC1)
    }
    Set:$$$StatusEquals(tSC,$$$EnsErrHTTPStatus) tSC=$$$OK
    Quit:$$$ISERR(tSC) tSC
    #; If no body response message, construct an ACK message from the HTTP Status Code
    If '$IsObject(pMsgIn) {
        //$$$TRACE("Component.Oauth.HL7HttpOperationPassThrough:Status " _ HttpResponse.StatusCode _ " " _ HttpResponse.StatusLine _ " " _ sessionId)
        Set pMsgIn=pMsgOut.NewReplyDocument()
        Set pMsgIn.Envelope="ACK_HTTP_"_+tHttpResponse.StatusCode_":"_tHttpResponse.StatusLine
        $$$TRACE("Component.Oauth.HL7HttpOperationPassThrough:Status " _ pMsgIn.Envelope)
        //Set tCode="A"_$Case(+tHttpResponse.StatusCode, 200:"A", 503:"R", :"E")
        //Set tCode = $Case(+tHttpResponse.StatusCode,  200:"AA", 204:"AA", 503:"AR", :"AE")
        // Full HTTP → HL7 MSA mapping
        Set tCode = $Case(+tHttpResponse.StatusCode,
            200:"AA", 201:"AA", 202:"AA", 204:"AA",
            400:"AE", 401:"AE", 403:"AE", 404:"AE",
            408:"AR", 429:"AR",
            500:"AR", 502:"AR", 503:"AR", 504:"AR",
            :"AE")
        #; Create a message object to represent the HTTP ACK ; set 00 control id, 2.1 version
        Do pMsgIn.SetValueAt($TR($P(pMsgIn.Envelope,":"),"_",pMsgIn.CS),"1:9")
        Set tControlId=pMsgOut.GetValueAt("1:10") Set tControlId=$S(""'=tControlId:tControlId,1:"00")
        Do pMsgIn.SetValueAt("00","1:10")
        Do pMsgIn.SetValueAt(2.1,"1:12")
        Set tDesc="HTTP "_$S("AA"=tCode:"",1:"(N)")_"ACK '"_tHttpResponse.StatusLine_"'"
        If $IsObject(tHttpResponse.Data) {
            Do tHttpResponse.Data.Rewind()
            Set tDesc=tDesc_$S('tHttpResponse.Data.Size:"",1:" : "_tHttpResponse.Data.Read(1000))
        }
        Set tMSAText="MSA"_pMsgIn.FS_tCode_pMsgIn.FS_tControlId_pMsgIn.FS_tDesc
        Set tAckMSA=##class(EnsLib.HL7.Segment).%New($LB(,1,,pMsgIn.Separators_tMSAText))
        Do pMsgIn.AppendSegment(tAckMSA)
    }
    Quit tSC
}
MethodAddAccessToken(ByRefpHttpRequestAs%Net.HttpRequest)As%Status
{
    $$$TRACE("Component.Oauth.HL7HttpOperationPassThrough:AddAccessToken")
    Set tSC = $$$OK
    #dim erroras%OAuth2.Error
    Try {
       
        ; sessionId has a 50 charactor limit
        ; This should support multiple requests in the same production session  
        Set sessionId=..OAuthTokenSessionId
        Set isAuthorised = ##class(%SYS.OAuth2.AccessToken).IsAuthorized(..OAuthClientApplicationName,sessionId,..OAuthScope,.accessToken,,.responseProperties,.error)
        ;Throw:'$$$NULLOREF=error ..ExceptionFromOAuth2Error(error)
        Throw:$isobject(error) ..ExceptionFromOAuth2Error(error)
        If 'isAuthorised {
            $$$TRACE("Component.Oauth.HL7HttpOperationPassThrough:AddAccessToken isAuthorised false")
            //Add any Parameters
            s paramsarr = [].%FromJSON(..Params)
            s iterator = paramsarr.%GetIterator()
            s properties=""
            While iterator.%GetNext(.key,.value)
            {
                s properties(key)=value
            }
            Set tSC = ##class(%SYS.OAuth2.Authorization).GetAccessTokenClient(..OAuthClientApplicationName,..OAuthScope,.properties,.error,.sessionId)    
            $$$TRACE("Component.Oauth.HL7HttpOperationPassThrough:AddAccessToken isAuthorised " _ tSC)
            Throw:$isobject(error) ..ExceptionFromOAuth2Error(error)
        }
        ; sendType is the mode of sending access token to resource server
        ; The default is "header"
        Set sendType = "header"
        ;The default for sslConfiguration comes from the OAuth2.Client instance.        
        Set tSC  = ##class(%SYS.OAuth2.AccessToken).AddAccessToken(pHttpRequest,sendType,,..OAuthClientApplicationName,sessionId)
    } Catch exception {
        Set tSC = exception.AsStatus()
        $$$TRACE("EXCEPTION")
        $$$TRACE("Component.Oauth.HL7HttpOperationPassThrough:AddAccessToken Code " _ exception.Code)
        $$$TRACE("Component.Oauth.HL7HttpOperationPassThrough:AddAccessToken Location " _ exception.Location)
        $$$TRACE("Component.Oauth.HL7HttpOperationPassThrough:AddAccessToken Data " _ exception.Data)
    }
    Return tSC
}
MethodSendRequest(OutputtHttpResponseAs%Net.HttpResponse,sendAs%String,tHttpRequestAs%Net.HttpRequest,OutputpResponseAsEnsLib.HTTP.GenericMessage)As%Status
{
    Set tSC=$$$OK
    // Perform the send
    Set tSC = ..Adapter.SendFormDataArray(.tHttpResponse, send, tHttpRequest)
    $$$TRACE("done the send")
    // If adapter returned error AND there's HTTP data, wrap the data in a status
    If $$$ISERR(tSC) && $IsObject(tHttpResponse) && $IsObject(tHttpResponse.Data) && tHttpResponse.Data.Size {
        Set tSC = $$$ERROR($$$EnsErrGeneral, $$$StatusDisplayString(tSC)_":"_tHttpResponse.Data.Read())
        Return tSC   // <-- FIX
    }
    If $$$ISERR(tSC) {
        Return tSC   // <-- FIX
    }
    // Handle HTTP status codes
    If (tHttpResponse.StatusCode < 300) {
        Set tSC=$$$OK
    } Else {
        Set message=tHttpResponse.StatusCode_": "_tHttpResponse.StatusLine_". "
        If $IsObject(tHttpResponse.Data) {
            Try {
                While 'tHttpResponse.Data.AtEnd {
                    Set message = message _ tHttpResponse.Data.Read(,.tSC1)
                }
            } Catch ex {
                // ignore
            }
        }
    }
    // Always RETURN a value
    Return ..constructResponse(tHttpResponse,.pResponse)
}
MethodconstructResponse(pHttpResponseAs%Net.HttpResponse,pResponseAsEnsLib.HTTP.GenericMessage)As%Status[Internal]
{
    $$$TRACE("construct response")
    Set tSC=$$$OK
    if '..CondensedHTMLResponse{
    If $IsObject(pHttpResponse.Data) {
        Set tStream=pHttpResponse.Data
    } Else {
        Set tStream=##class(%Stream.GlobalBinary).%New()
        Set tSC=tStream.Write(pHttpResponse.Data)  Quit:$$$ISERR(tSC) tSC
    }
    Set pResponse=##class(EnsLib.HTTP.GenericMessage).%New(tStream,,pHttpResponse)
    }
    else{
    Set pResponse=##class(EnsLib.HTTP.GenericMessage).%New()
        }
    Do pResponse.HTTPHeaders.SetAt(pHttpResponse.StatusCode,"StatusCode")
    Do pResponse.HTTPHeaders.SetAt(pHttpResponse.StatusLine,"StatusLine")
    Quit tSC
}
MethodExceptionFromOAuth2Error(pErrorAs%OAuth2.Error)As%Exception.StatusException
{
    Set errorText = pError.AsString()
    $$$LOGERROR(errorText)
    Set tSC = $$$ERROR($$$GeneralError,errorText)
    Return ##class(%Exception.StatusException).CreateFromStatus(tSC)
    ;Or
    ;If you wish to create one with %New then the 4th argument is a $lb of data values to the error %Status, e.g.
    ;Set exception = ##class(%Exception.StatusException).%New(Name,Code,Location,$lb(arg1,arg2,arg3,arg4))
}
}
Dean White · Sep 27, 2024 go to post

Something like this operation should do it for you.
 

Class Component.Outbound.JsonHttpsOut Extends Ens.BusinessOperation
{

Parameter ADAPTER = "EnsLib.HTTP.OutboundAdapter";

Property Adapter As EnsLib.HTTP.OutboundAdapter;

Method SendMessage(pMsgOut As %DynamicObject, Output pMsgIn As %Net.HttpResponse) As %Status
{
    S tSC=$$$OK
    Set tHttpRequest=##class(%Net.HttpRequest).%New(), tHttpRequest.WriteRawMode=1, token =##class(%DynamicObject).%New(), tSC=$$$OK
    Set tHttpRequest.SSLConfiguration=..Adapter.SSLConfig
    Set tSC = tHttpRequest.SetHeader("Content-Type", ..ContentType)
    d tHttpRequest.EntityBody.Write(pMsgOut.%ToJSON())
    #dim tHttpResponse As %Net.HttpResponse
    Set tHttpResponse = ##class(%Net.HttpResponse).%New()
    S send="POST"
    Set tSC=..Adapter.SendFormDataArray(.tHttpResponse, send, tHttpRequest)
    if (tHttpResponse.StatusCode="200"){
        set message=tHttpResponse.StatusCode_": "_tHttpResponse.StatusLine_". "
        if $IsObject(tHttpResponse.Data) 
        {
               while 'tHttpResponse.Data.AtEnd {
                   set message=message_tHttpResponse.Data.Read(,.tSC1) 
                   if 'tSC1 quit
            }
            $$$TRACE(message)
            s tSC=$$$ERROR("9999",message)
        }
        s tSC=$$$OK
        }
    else
    {
        set message=tHttpResponse.StatusCode_": "_tHttpResponse.StatusLine_". "
        if $IsObject(tHttpResponse.Data) 
        {
               //set message="" 
               while 'tHttpResponse.Data.AtEnd {
                   set message=message_tHttpResponse.Data.Read(,.tSC1) 
                   if 'tSC1 quit
            }
            $$$TRACE(message)
            s tSC=$$$ERROR("9999",message)
        }
        Set ..Adapter.URL=$REPLACE(..Adapter.URL,..tmpurl,"")    //sets adapter url back to standard if it was last used to remove an MRN
    }

    Q tSC
}

Dean White · Sep 18, 2024 go to post

You can do something similar by doing all transfroms in something like 2.4 ADT_A01, and then using code similar to below on all transforms to change the message Doctype to match the intended schema.

 //this part collates the info to set the doctype

 set version=target.GetValueAt("MSH:VersionID.versionID")

 set type=target.GetValueAt("MSH:MessageType.messagetype")

 set trigger=target.GetValueAt("MSH:MessageType.triggerevent")

 //set trigger="A05"

 if ((trigger = "A08")!(trigger = "A11")!(trigger = "A27")!(trigger = "A03")!(trigger = "A12")!(trigger = "A13")){SET trigger = "A01"}

 //this sets the doctype

 set target.DocType=version_":"_type_"_"_trigger

 //set target.DocType="2.4:ADT_A05"

 ]]></code>

Dean White · Jun 28, 2024 go to post

#dim tResponse As HS.FHIRServer.Interop.Response
Set tSC = ..SendRequestSync(..TargetConfigName, tRequest, .tResponse)
if (($P(tResponse.Response.Status," ",1)>199) && ($P(tResponse.Response.Status," ",1)<399))
{ Set tResponseQuickStream = ##class(HS.SDA3.QuickStream).%OpenId(tResponse.QuickStreamId)
Set tSC = $$$ERROR($$$GeneralError, tResponseQuickStream.Read())
//Set BundleObject=##class(HS.FHIR.DTL.vR4.Model.Resource.Bundle).FromJSON(tResponseQuickStream,"vR4")
Set BundleObject=##class(%DynamicObject).%FromJSON(tResponseQuickStream)
}

Dean White · May 30, 2024 go to post

if (($P(tResponse.Response.Status," ",1)>199) && ($P(tResponse.Response.Status," ",1)<399))
{
Set tResponseQuickStream = ##class(HS.SDA3.QuickStream).%OpenId(tResponse.QuickStreamId)
Set tSC = $$$ERROR($$$GeneralError, tResponseQuickStream.Read())
Set BundleObject=##class(HS.FHIR.DTL.vR4.Model.Resource.Bundle).FromJSON(tResponseQuickStream,"vR4")
Quit BundleObject
}

You can use the line similar to below instead of Bundle if you are unsure of the payload as well

BundleObject=##class(%DynamicObject).%FromJSON(tResponseQuickStream)

Dean White · Sep 6, 2023 go to post

We sent the EnsLib.HTTP.GenericService into a process that did this, hope it helps.

Include Ensemble

Class Component.httpResendMessage Extends Ens.BusinessProcess
{

Method OnRequest(pRequest As EnsLib.HTTP.GenericMessage, Output pResponse As EnsLib.HTTP.GenericMessage) As %Status
{     

    set tSC=$$$OK
    namespace = $REPLACE(pRequest.HTTPHeaders.GetAt("IParams_1"),"namespace=","")
    ClientDocGUID= $REPLACE(pRequest.HTTPHeaders.GetAt("IParams_2"),"ClientDocGUID=","")
   

   s pResponse=##class(EnsLib.HTTP.GenericMessage).%New()
   set pResponseBody=##Class(%Stream.GlobalCharacter).%New()
   d pResponseBody.Write("<HTML><HEAD>Uh oh.</HEAD><BODY><BR><STRONG>Error: Invalid Patient ID</STRONG></BODY></HTML>")
   do pResponseBody.Rewind()
   d pResponse.HTTPHeaders.SetAt("HTTP/1.1 400 Bad Request","StatusLine")
   d pResponse.HTTPHeaders.SetAt("text/html; charset=utf-8","Content-Type")
   do pResponse.StreamSet(pResponseBody)
quit tSC
}  

}

Dean White · May 31, 2023 go to post

go into the terminal and the namespace you want to disable, then type Set ^%SYS("sql","sys","autotune") = 0

Dean White · May 19, 2023 go to post

You could also try adding a code section to you DTL, similar to this.

//this part collates the info to set the doctype
 set version=target.GetValueAt("MSH:VersionID.versionID")
 set type=target.GetValueAt("MSH:MessageType.messagetype")
 set trigger=target.GetValueAt("MSH:MessageType.triggerevent")
 //set trigger="A05"
 if ((trigger = "A08")!(trigger = "A11")!(trigger = "A27")!(trigger = "A03")!(trigger = "A12")!(trigger = "A13")){SET trigger = "A01"}
 //this sets the doctype
 set target.DocType=version_":"_type_"_"_trigger
 //set target.DocType="2.4:ADT_A05"