Exemple de classe utilisant un index IDKEY
 
Test

Réponse de @Ashok Kumar 

Bonjour @Muhammad Waseem 

Vous pouvez peut-être essayer d'extraire la ressource patient du bundle ou l'utiliser si c'est déjà une ressource. Chargez la classe du modèle patient FHIR HS.FHIR.DTL.vR4.Model.Resource.Patient avec la ressource extraite. Ensuite, vous pouvez convertir la date de naissance et valider l'âge. Vous pouvez utiliser la même logique dans votre code DTL dans un processus FHIR entre le service FHIR (HS.FHIRServer.Interop.Service) et l'opération FHIR (HS.FHIRServer.Interop.Operation).

ClassMethod VaidatePatientResource(patientResourceStreram As %Stream.Object)
{
	#dim patient As HS.FHIR.DTL.vR4.Model.Resource.Patient
	try {
		set patient = ##class(HS.FHIR.DTL.vR4.Model.Resource.Patient).FromJSON(patientResourceStreram)
		Set age = $horolog - $ZdateH(patient.birthDate,3)\360
		if age<18 $$$ThrowStatus($$$ERROR($$$GeneralError, "Age is less than 18"))
	}
	catch ex {
		w ex.DisplayString()
	}
}

Bonjour @Julia Pertin 
peux-tu me donner plus de détails sur l'erreur rencontrée ?

Vérifies-bien si tu recrées une production from scratch, en ajoutant service-process-operation, de conserver les noms les BS-BP-BO identiques aux noms des 3 classes EP.service.replication, EP.process.replication et EP.operation.replication, et qu'ils sont bien reliés entre eux.
 

Le code de la Business Opération

Class EP.operation.replication Extends Ens.BusinessOperation
{

Property Adapter As Ens.OutboundAdapter;

Parameter ADAPTER = "Ens.OutboundAdapter";

Parameter INVOCATION = "Queue";

Method sync(pRequest As Ens.StreamContainer, Output pResponse As Ens.StringContainer) As %Status
{
    set pResponse = ##class(Ens.StringContainer).%New()
    set json = [].%FromJSON(pRequest.Stream)
    set array = json.%GetIterator()
    while array.%GetNext(.key,.value) {
        $$$TRACE("Data:"_value.%ToJSON())
        set a = ##class(data.client2).%New()
        set sc = a.%JSONImport(value)
        if 'sc {
            $$$LOGERROR("ERROR while importing:"_$system.Status.GetErrorText(sc))
        } else {
            set sc = a.%Save()
        }
    }
    set pResponse.StringValue = key _" records inserted"
    return sc
}

XData MessageMap
{
<MapItems>
    <MapItem MessageType="Ens.StreamContainer">
        <Method>sync</Method>
    </MapItem>
</MapItems>
}

}

Le code du Business Process

Class EP.process.replication Extends Ens.BusinessProcess [ ClassType = persistent, ProcedureBlock ]
{

Property Server As %String [ InitialExpression = "host.docker.internal" ];

Property Port As %Integer [ InitialExpression = 12773 ];

Property classname As %String [ InitialExpression = "data.client" ];

Parameter SETTINGS = "Server:target,Port:target,classname:target";

Method OnRequest(pRequest As Ens.Request, Output pResponse As Ens.StringContainer) As %Status
{
    set sc = $$$OK
    set tHttpRequest             = ##class(%Net.HttpRequest).%New()
    set pContainer               = ##class(Ens.StreamContainer).%New()
    set stream                   = ##class(%Stream.GlobalCharacter).%New()
    set tHttpRequest.Server      = ..Server
    set tHttpRequest.Port        = ..Port
    set location                 = "/common/list/" _ ..classname _ "/json"

    set tHttpRequest.ContentType = "application/json"
    set tHttpRequest.Timeout     = 900
    
    set tSC = tHttpRequest.Get(location)
  
   if $ISOBJECT(tHttpRequest.HttpResponse) {
    Set jsonObject               = [].%FromJSON(tHttpRequest.HttpResponse.Data)
    Do jsonObject.%ToJSON(.stream)
    set pContainer.Stream = stream
    $$$TRACE("stream size:"_stream.Size)
    $$$TRACE("stream data:"_stream.Read(1000))

    set sc = ..SendRequestSync("EP.operation.replication",pContainer,.pResponse)
    
   }
   return sc
}

Storage Default
{
<Data name="replicationDefaultData">
<Subscript>"replication"</Subscript>
<Value name="1">
<Value>Server</Value>
</Value>
<Value name="2">
<Value>Port</Value>
</Value>
<Value name="3">
<Value>classname</Value>
</Value>
</Data>
<DefaultData>replicationDefaultData</DefaultData>
<Type>%Storage.Persistent</Type>
}

}

Le code du Business Service :
 

Class EP.service.replication Extends Ens.BusinessService
{

Property Adapter As Ens.InboundAdapter;

Parameter ADAPTER = "Ens.InboundAdapter";

Property TargetConfigNames As %String(MAXLEN = 1000);

Property sync As %Boolean [ InitialExpression = 1 ];

Parameter SETTINGS = "sync:Advanced,TargetConfigNames:Basic:selector?multiSelect=1&context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId}";

Method OnProcessInput(pInput As %RegisteredObject, Output pResponse As Ens.StringResponse) As %Status
{
  set tSC = $$$OK
  for iTarget=1:1:$L(..TargetConfigNames, ",") {
        set tOneTarget=$ZStrip($P(..TargetConfigNames,",",iTarget),"<>W")  Continue:""=tOneTarget
        $$$TRACE("The target '"_tOneTarget_"' will be called "_$SELECT(..sync=1:"synchronously",..sync=0:"synchronously"))
        if ..sync {
          set tSC1=..SendRequestSync(tOneTarget,pInput,.pResponse)  Set:$$$ISERR(tSC1) tSC=$$$ADDSC(tSC,tSC1)
        } else {
          set tSC1=..SendRequestAsync(tOneTarget,pInput)  Set:$$$ISERR(tSC1) tSC=$$$ADDSC(tSC,tSC1)
        }
  }
  return tSC
}

/// Return an array of connections for drawing lines on the config diagram
ClassMethod OnGetConnections(Output pArray As %String, pItem As Ens.Config.Item)
{
	Do ##super(.pArray,pItem)
	If pItem.GetModifiedSetting("TargetConfigNames",.tValue) {
		For i=1:1:$L(tValue,",") { Set tOne=$ZStrip($P(tValue,",",i),"<>W")  Continue:""=tOne  Set pArray(tOne)="" }
	}
}

}

Bonjour @Julia Pertin,

si j'ai bien compris ton besoin, pour régler ton problème qui consiste à éviter de récupérer plusieurs fois le même flux json, ton Business Service doit servir uniquement à appeler un Business Process, qui lui va se charger de récupérer le flux json pour le passer à une Business Operation.

Dans le cas où ton Business Service appelle le Business Process de manière synchrone, il attendra bien la réponse avant de s'exécuter à nouveau.
Dans le cas contraire, c'est à dire si le Business Process est appelé de manière asynchrone, le Business Service fera un nouvel appel à chaque atteinte du temps prévu par le paramètre "
INTERVALLE ENTRE APPELS".

  

Réponse de @Dmitry Maslennikov 

Pour quelques versions déjà, Caché et IRIS prennent déjà en charge OAuth2 dès le départ. Regardez la documentation.

Cela dépend de votre architecture, vous pouvez utiliser cette méthode ou utiliser n'importe quel fournisseur d'identité externe comme keycloack.

Et je pense qu'IAM peut également vous aider.

Réponse de @Rob Tweed 

Nous avons deux produits Open Source qui prendront en charge les JWT pour vous de la manière correspondant à ce que vous demandez (c'est-à-dire les services REST avec IRIS) :

- QEWD, si vous souhaitez tout implémenter en back-end dans Node.js / JavaScript

- mgweb-server si vous souhaitez utiliser la logique ObjectScript pour votre logique back-end

Pour QEWD et IRIS, voir :

https://github.com/robtweed/qewd-starter-kit-iris-networked

En particulier pour les services REST, voir :

https://github.com/robtweed/qewd-starter-kit-iris-networked/blob/master/...

et plus précisément cette section:

https://github.com/robtweed/qewd-starter-kit-iris-networked/blob/master/...

Pour le serveur mgweb, voir :

https://github.com/robtweed/mgweb-server

spécifiquement utilisé avec IRIS :

https://github.com/robtweed/mgweb-server/blob/master/IRIS.md

et dans ce document, cette section sur les JWT :

https://github.com/robtweed/mgweb-server/blob/master/IRIS.md#using-json-...

Rob