// CreateResource creates an instance of the resource associated with // the request url, writes the body of the request into the new object, // and then persists the object in the database. A unique identifier is // created and associated with the object. A copy of the object that was // stored in the database is returned in the response. func (rc *ResourceController) CreateResource(ctx *gin.Context) { req := ctx.Request resourceType := getResourceType(req.URL) resource := ptm_models.NewStructForResourceName(resourceType) if err := ctx.Bind(resource); err != nil { ctx.AbortWithError(http.StatusBadRequest, err) return } res, err := ptm_models.PersistResource(rc.Database(), resourceType, resource) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, err) return } id := reflect.ValueOf(res).Elem().FieldByName("ID").String() logger.Log.WithFields( logrus.Fields{"res type": resourceType, "id": id}).Info("CreateResource") ctx.Header("Location", responseURL(req, resourceType, id).String()) ctx.JSON(http.StatusCreated, res) }
func (s *ServerSuite) TestRecordMatchRunResponse(c *C) { var r interface{} // Insert a record match run object to the DB // r := ptm_models.InsertResourceFromFile(Database(), "RecordMatchRun", "../fixtures/record-match-run-01.json") recMatchRun := &ptm_models.RecordMatchRun{} ptm_models.LoadResourceFromFile("../fixtures/record-match-run-01.json", recMatchRun) // recMatchRun := r.(*ptm_models.RecordMatchRun) c.Assert(*recMatchRun, NotNil) // confirm initial state - zero responses assoc. w/ run c.Assert(len(recMatchRun.Responses), Equals, 0) // Assign New Identifier to request message // recMatchRun.Request.Message.Enry[0].Resource.ID = bson.NewObjectId() reqMsg := recMatchRun.Request.Message reqMsgHdr := reqMsg.Entry[0].Resource.(*fhir_models.MessageHeader) recMatchRun.Request.ID = bson.NewObjectId() reqMsg.Id = bson.NewObjectId().Hex() reqMsgHdr.Id = bson.NewObjectId().Hex() ptm_models.PersistResource(Database(), "RecordMatchRun", recMatchRun) logger.Log.WithFields( logrus.Fields{"func": "TestRecordMatchRunResponse", "recMatchRun": recMatchRun}).Info("after insert recMatchRun") respMsg := &fhir_models.Bundle{} // Load text of a record match ack message ptm_models.LoadResourceFromFile("../fixtures/record-match-ack-01.json", respMsg) //respMsg := r.(*fhir_models.Bundle) c.Assert(*respMsg, NotNil) // Ensure the response references the request // reqMsg := recMatchRun.Request.Message c.Assert(reqMsg, NotNil) c.Assert(reqMsg.Type, Equals, "message") c.Assert(len(reqMsg.Entry) > 1, Equals, true) c.Assert(reqMsg.Entry[0].Resource, NotNil) // reqMsgHdr := reqMsg.Entry[0].Resource.(*fhir_models.MessageHeader) respMsgHdr := respMsg.Entry[0].Resource.(*fhir_models.MessageHeader) respMsgHdr.Response.Identifier = reqMsgHdr.Id buf, _ := respMsg.MarshalJSON() logger.Log.WithFields( logrus.Fields{"func": "TestRecordMatchRunResponse", "resp msg": string(buf)}).Info("prep to POST") e := s.Server.Engine code, body := request("POST", "/Bundle", bytes.NewReader(buf), "application/json", e) c.Assert(code, Equals, http.StatusCreated) c.Assert(body, NotNil) logger.Log.Info("Post Record Match response: " + body) // Load the record match run object -- this time from database r, err := ptm_models.LoadResource(Database(), "RecordMatchRun", recMatchRun.ID) c.Assert(err, IsNil) c.Assert(r, NotNil) recMatchRun = r.(*ptm_models.RecordMatchRun) logger.Log.WithFields( logrus.Fields{"func": "TestRecordMatchRunResponse", "recMatchRun": recMatchRun}).Info("after recv response") // The response should be attached to the record match run ObjectId c.Assert(len(recMatchRun.Responses), Equals, 1) c.Assert(recMatchRun.Responses[0].ID, NotNil) c.Assert(recMatchRun.Responses[0].Message, NotNil) var respMsg1 *fhir_models.Bundle respMsg1 = recMatchRun.Responses[0].Message // After inserting into database, we've lost knowledge about type of resource in response message // so we use hack to decode to and then encode from json to get map to struct respMsgHdr1 := &fhir_models.MessageHeader{} mapToStruct(respMsg1.Entry[0].Resource.(bson.M), respMsgHdr1) c.Assert(respMsgHdr1.Response.Identifier, Equals, respMsgHdr.Response.Identifier) }
// CreateRecordMatchRunHandler creates a HandlerFunc that creates a new // RecordMatchRun and constructs and sends a Record Match request message. func CreateRecordMatchRunHandler(provider func() *mgo.Database) gin.HandlerFunc { return func(ctx *gin.Context) { recMatchRun := &ptm_models.RecordMatchRun{} if err := ctx.Bind(recMatchRun); err != nil { ctx.AbortWithError(http.StatusInternalServerError, err) return } if !isValidRecordMatchRun(recMatchRun) { // Bad Request: Record Match Run contains invalid content ctx.String(http.StatusBadRequest, "Invalid RecordMatchRun content") ctx.Abort() return } // retrieve and validate the record match context recMatchContextID := recMatchRun.RecordMatchContextID logger.Log.WithFields( logrus.Fields{"method": "CreateRecordMatchRun", "recMatchContextID": recMatchContextID}).Debug("check recmatch config id") if !recMatchContextID.Valid() { // Bad Request: Record Match Context is optional but must be valid, if provided ctx.String(http.StatusBadRequest, "Invalid RecordMatchContextID") ctx.Abort() return } // Retrieve the info about the record matcher obj, err := ptm_models.LoadResource(provider(), "RecordMatchSystemInterface", recMatchRun.RecordMatchSystemInterfaceID) if err != nil { ctx.String(http.StatusBadRequest, "Unable to find Record Match System Interface") ctx.Abort() return } recMatchSysIface := obj.(*ptm_models.RecordMatchSystemInterface) if !isValidRecordMatchSysIface(recMatchSysIface) { ctx.String(http.StatusBadRequest, "Invalid Record Match System Interface") ctx.Abort() return } // construct a record match request reqMatchRequest, err := newRecordMatchRequest(recMatchSysIface.ResponseEndpoint, recMatchRun, provider()) if err != nil { logger.Log.WithFields( logrus.Fields{"method": "CreateRecordMatchRun", "err": err}).Warn("Unable to create Record Match Request") ctx.AbortWithError(http.StatusBadRequest, err) return } // attach the request message to the run object recMatchRun.Request = *reqMatchRequest // Construct body of the http request for the record match request reqBody, _ := reqMatchRequest.Message.MarshalJSON() svrEndpoint := prepEndpoint(recMatchSysIface.ServerEndpoint, reqMatchRequest.Message.Id) logger.Log.WithFields( logrus.Fields{"method": "CreateRecordMatchRun", "server endpoint": svrEndpoint, "reqBody": string(reqBody[:]), "message": reqMatchRequest.Message}).Info("About to submit request") reqMatchRequest.SubmittedOn = time.Now() // Send the record match request to a FHIR server acting as msg broker. resp, err := ptm_http.Put(svrEndpoint, "application/json+fhir", bytes.NewReader(reqBody)) if err != nil { // HACK In this configuration, the test harness only supports itself as the FHIR message broker if resp.StatusCode == 302 { logger.Log.Debug("CreateRecordMatchRun: redirect detected - Infer server is in Heart mode") _, err = ptm_models.PersistFhirResource(provider(), "Bundle", reqMatchRequest.Message) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, err) return } } else { logger.Log.WithFields( logrus.Fields{"method": "CreateRecordMatchRun", "err": err}).Warn("Sending Record Match Request") ctx.AbortWithError(http.StatusInternalServerError, err) return } } logger.Log.WithFields( logrus.Fields{"method": "CreateRecordMatchRun", "status": resp.StatusCode}).Info("Put Response Status") // Store status, Sent, with the run object recMatchRun.Status = make([]ptm_models.RecordMatchRunStatusComponent, 1) recMatchRun.Status[0].CreatedOn = time.Now() // if a success code was received if resp.StatusCode >= 200 && resp.StatusCode < 300 { recMatchRun.Status[0].Message = "Request Sent [" + resp.Status + "]" } else if resp.StatusCode == 302 { recMatchRun.Status[0].Message = "Redirect from Msg Broker Not Supported; Request persisted in local database" } else { recMatchRun.Status[0].Message = "Error Sending Request to Record Matcher [" + resp.Status + "]" } // Persist the record match run resource, err := ptm_models.PersistResource(provider(), "RecordMatchRun", recMatchRun) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, err) return } ctx.JSON(http.StatusCreated, resource) } }