func SearchSourceHandler(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) source := strings.ToLower(vars["source"]) if !validElasticSearchRegexp.MatchString(source) { api.Render(w, req, http.StatusOK, map[string]interface{}{ "meta": map[string]interface{}{ "rowCount": 0, }, "result": []string{}, }) return } params, err := ParseSearchParams(req.URL.Query()) if err != nil { api.Render(w, req, http.StatusBadRequest, err) return } results, err := Search(source, params, req) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } api.Render(w, req, http.StatusOK, results) return }
func NpiSearchHandler(w http.ResponseWriter, req *http.Request) { params, err := handler.ParseSearchParams(req.URL.Query()) if err != nil { api.Render(w, req, http.StatusBadRequest, err) return } results, err := handler.Search("usgov.hhs.npi", params, req) if err != nil { switch err.(type) { case api.ParamsError: api.Render(w, req, http.StatusBadRequest, err) return default: log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } } valuesToStrings(results) api.AddFeature(req, "usgov.hhs.npi") api.AddFeature(req, "handler:legacynpi:search") api.Render(w, req, http.StatusOK, results) return }
func SourcesHandler(w http.ResponseWriter, req *http.Request) { conn, err := api.Conn().SqlConnection() if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } rows, err := conn.Query("SELECT name, last_updated, last_checked FROM search_types") if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } defer rows.Close() var ( source string update time.Time checked time.Time ) var npiUpdated, npiChecked time.Time sources := make([]dataSource, 0) for rows.Next() { err := rows.Scan(&source, &update, &checked) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } // Backcompat Feb 13, 2015 if source == "usgov.hhs.npi" { npiUpdated = update npiChecked = checked } sources = append(sources, dataSource{source, update, checked, "READY"}) } // Backcompat Feb 13, 2015 sources = append(sources, dataSource{"NPI", npiUpdated, npiChecked, "READY"}) api.Render(w, req, http.StatusOK, map[string][]dataSource{"result": sources}) }
func (s *Authentication) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { vars := r.URL.Query() secret := vars["secret"] if len(secret) > 1 { api.Render(rw, r, 401, map[string]string{ "name": "Unauthorized", "message": "Please contact [email protected] if this is in error", }) return } if len(secret) == 1 { conn, err := api.Conn().SqlConnection() if err != nil { log.Println(err) api.Render(rw, r, http.StatusInternalServerError, "Internal Server Error") return } var deactivated bool err = conn.QueryRow(`SELECT deactivated FROM api_keys WHERE key = $1`, secret[0]).Scan(&deactivated) if err == sql.ErrNoRows { api.Render(rw, r, 401, map[string]string{ "name": "Unauthorized", "message": "Please contact [email protected] if this is in error", }) return } else if deactivated { api.Render(rw, r, 401, map[string]string{ "name": "Deactivated", "message": "Your account has been deactivated by BloomAPI admins. Please contact [email protected] for more information", }) return } else if err != nil { log.Println(err) api.Render(rw, r, http.StatusInternalServerError, "Internal Server Error") return } context.Set(r, "api_key", secret[0]) next(rw, r) } else { next(rw, r) } }
func NpiItemHandler(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) npi := vars["npi"] conn := api.Conn().SearchConnection() result, err := conn.Search("usgov.hhs.npi", "main", nil, map[string]interface{}{ "query": map[string]interface{}{ "filtered": map[string]interface{}{ "filter": map[string]interface{}{ "term": map[string]interface{}{ "npi": npi, }, }, }, }, }) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } if result.Hits.Total == 0 { api.Render(w, req, http.StatusNotFound, "npi not found") return } else { hits := make([]interface{}, len(result.Hits.Hits)) for i, hit := range result.Hits.Hits { var source map[string]interface{} json.Unmarshal(*hit.Source, &source) hits[i] = source } body := map[string]interface{}{"result": hits[0]} valuesToStrings(body) api.AddFeature(req, "usgov.hhs.npi") api.AddFeature(req, "handler:legacynpi:item") api.Render(w, req, http.StatusOK, body) return } }
func SourcesHandler(w http.ResponseWriter, req *http.Request) { conn := api.Conn() apiKey, ok := context.Get(req, "api_key").(string) if !ok { apiKey = "" } searchTypes, err := conn.SearchTypesWithKey(apiKey) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } sources := []dataSource{} for _, searchType := range searchTypes { sources = append(sources, dataSource{ Source: searchType.Name, Updated: searchType.LastUpdated, Checked: searchType.LastChecked, Status: "READY", }) // Backcompat Feb 13, 2015 if searchType.Name == "usgov.hhs.npi" { sources = append(sources, dataSource{ Source: "NPI", Updated: searchType.LastUpdated, Checked: searchType.LastChecked, Status: "READY", }) } } api.AddFeature(req, "handler:sources") api.Render(w, req, http.StatusOK, map[string][]dataSource{"result": sources}) }
func (s *Authentication) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { vars := r.URL.Query() secret := vars["secret"] if len(secret) > 0 && secret[0] != "" { api.Render(rw, r, 401, map[string]string{ "name": "Unauthorized", "message": "Please contact [email protected] if this is in error", }) } else { next(rw, r) } }
func SearchSourceHandler(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) source := strings.ToLower(vars["source"]) conn := api.Conn() apiKey, ok := context.Get(req, "api_key").(string) if !ok { apiKey = "" } _, ok, err := conn.SearchTypeWithNameAndKey(source, apiKey) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } if !ok { api.Render(w, req, 404, map[string]string{ "name": "Source Not Found", "message": "Please contact [email protected] if this is in error", }) return } params, err := ParseSearchParams(req.URL.Query()) if err != nil { api.Render(w, req, http.StatusBadRequest, err) return } results, err := Search(source, params, req) if err != nil { if _, ok = err.(api.ParamsError); ok { api.Render(w, req, http.StatusBadRequest, err) } else { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") } return } api.AddFeature(req, source) api.AddFeature(req, "handler:search") api.Render(w, req, http.StatusOK, results) return }
func ItemHandler(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) source := strings.ToLower(vars["source"]) id := vars["id"] conn := api.Conn().SearchConnection() if !validElasticSearchRegexp.MatchString(source) { api.Render(w, req, http.StatusNotFound, "item not found") return } if !validElasticSearchRegexp.MatchString(id) { api.Render(w, req, http.StatusNotFound, "item not found") return } if source != "usgov.hhs.npi" { api.AddMessage(req, "Warning: Use of the dataset, '"+source+"', without an API key is for development-use only. Use of this API without a key may be rate-limited in the future. For hosted, production access, please email '*****@*****.**' for an API key.") api.AddMessage(req, "Warning: This query used the experimental dataset, '"+source+"'. To ensure you're notified in case breaking changes need to be made, email [email protected] and ask for an API key.") } result, err := conn.Get("source", source, id, nil) if err != nil && err.Error() == elastigo.RecordNotFound.Error() { api.Render(w, req, http.StatusNotFound, "item not found") return } else if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } var found map[string]interface{} err = json.Unmarshal(*result.Source, &found) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } body := map[string]interface{}{"result": found} api.Render(w, req, http.StatusOK, body) return }
func YourChartCreateHandler(w http.ResponseWriter, req *http.Request) { yourchartUrl := viper.GetString("yourchartUrl") //yourchartLabUrl := viper.GetString("yourchartLabUrl") username := req.FormValue("username") password := req.FormValue("password") orgId := req.FormValue("orgId") apiKey, ok := context.Get(req, "api_key").(string) enabled, err := YourchartEnabled(apiKey) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } if !ok || !enabled { api.Render(w, req, 404, map[string]string{ "name": "Source Not Found", "message": "Please contact [email protected] if this is in error", }) return } jobId := uuid.NewV4().String() // Yourchart postResp, err := http.PostForm(yourchartUrl, url.Values{ "username": {username}, "password": {password}, "orgId": {orgId}, }) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } defer postResp.Body.Close() body, err := ioutil.ReadAll(postResp.Body) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } var decoded map[string]interface{} decoder := json.NewDecoder(strings.NewReader(string(body))) err = decoder.Decode(&decoded) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } var upstreamJobId string rawUpstreamJobId, ok := decoded["statusId"] if !ok { log.Println(errors.New("Unable to get new job's statusId")) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } // Yourchart Lab!! /*postLabResp, err := http.PostForm(yourchartLabUrl, url.Values{ "username": {username}, "password": {password}, "orgId": {orgId}, }) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } defer postLabResp.Body.Close() labBody, err := ioutil.ReadAll(postLabResp.Body) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } var labDecoded map[string]interface{} labDecoder := json.NewDecoder(strings.NewReader(string(labBody))) err = labDecoder.Decode(&labDecoded) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } var upstreamLabJobId string rawUpstreamLabJobId, ok := labDecoded["statusId"] if !ok { log.Println(errors.New("Unable to get new job's statusId")) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } switch rawUpstreamLabJobId := rawUpstreamLabJobId.(type) { case string: upstreamLabJobId = rawUpstreamLabJobId case float64: upstreamLabJobId = strconv.FormatFloat(rawUpstreamLabJobId, 'f', 0, 64) }*/ switch rawUpstreamJobId := rawUpstreamJobId.(type) { case string: upstreamJobId = rawUpstreamJobId case float64: upstreamJobId = strconv.FormatFloat(rawUpstreamJobId, 'f', 0, 64) } err = YourchartAuthorize(apiKey, jobId, upstreamJobId, "") if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } api.AddFeature(req, "handler:yourchart:create") api.Render(w, req, http.StatusOK, map[string]string{ "statusId": jobId, }) }
func YourChartFetchHandler(w http.ResponseWriter, req *http.Request) { raven.SetHttpContext(raven.NewHttp(req)) vars := mux.Vars(req) yourchartUrl := viper.GetString("yourchartUrl") yourchartLabUrl := viper.GetString("yourchartLabUrl") id := vars["id"] apiKey, ok := context.Get(req, "api_key").(string) enabled, err := YourchartEnabled(apiKey) if err != nil { log.Println(err) raven.CaptureErrorAndWait(err, nil) api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"}) return } upstreamJobId, upstreamLabJobId, err := YourchartAuthorized(apiKey, id) if err != nil { log.Println(err) raven.CaptureErrorAndWait(err, nil) api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"}) return } if !ok || !enabled || upstreamJobId == "" { api.Render(w, req, 404, map[string]string{ "name": "Source Not Found", "message": "Please contact [email protected] if this is in error", }) return } getResp, err := http.Get(yourchartUrl + "/" + upstreamJobId) body, err := ioutil.ReadAll(getResp.Body) if err != nil { log.Println(err) raven.CaptureErrorAndWait(err, nil) api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"}) return } var decoded map[string]interface{} decoder := json.NewDecoder(strings.NewReader(string(body))) err = decoder.Decode(&decoded) if err != nil { log.Println(err) raven.CaptureErrorAndWait(err, nil) api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"}) return } api.AddFeature(req, "handler:yourchart:fetch") if upstreamLabJobId == "" { api.Render(w, req, http.StatusOK, decoded) return } getLabResp, err := http.Get(yourchartLabUrl + "/" + upstreamLabJobId) labBody, err := ioutil.ReadAll(getLabResp.Body) if err != nil { log.Println(err) raven.CaptureErrorAndWait(err, nil) api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"}) return } var labDecoded map[string]interface{} labDecoder := json.NewDecoder(strings.NewReader(string(labBody))) err = labDecoder.Decode(&labDecoded) if err != nil { log.Println(err) raven.CaptureErrorAndWait(err, nil) api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"}) return } state, ok := decoded["state"].(string) if !ok { api.Render(w, req, 404, map[string]string{ "name": "Source Not Found", "message": "Please contact [email protected] if this is in error", }) return } if state != "complete" { api.Render(w, req, http.StatusOK, decoded) return } labState, ok := labDecoded["state"].(string) if !ok { api.Render(w, req, 404, map[string]string{ "name": "Source Not Found", "message": "Please contact [email protected] if this is in error", }) return } if labState == "pending" { api.Render(w, req, http.StatusOK, map[string]string{"state": "authenticated"}) return } else if labState != "complete" { raven.CaptureErrorAndWait(errors.New("lab job seems to be in failure state"), nil) api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"}) return } patients := decoded["result"].(map[string]interface{})["patients"].([]interface{}) for iOne, patient := range patients { //name := patient.(map[string]interface{})["name"].(string) details := patient.(map[string]interface{})["details"] replaced := false labPatients := labDecoded["result"].(map[string]interface{})["patients"].([]interface{}) if len(labPatients) == 0 { raven.CaptureErrorAndWait(errors.New("no lab patients returned"), nil) api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"}) return } newModel := labPatients[0].(map[string]interface{})["test-results"] != nil if newModel && len(patients) != len(labPatients) { raven.CaptureErrorAndWait(errors.New("number of patients are different"), nil) api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"}) return } if newModel { // New version Jan 25, 2016 for iTwo, labPatient := range labPatients { //labName := labPatient.(map[string]interface{})["name"].(string) //labDetails := labPatient.(map[string]interface{})["details"] if iOne == iTwo { if labPatient.(map[string]interface{})["name"] != nil && patient.(map[string]interface{})["name"] != labPatient.(map[string]interface{})["name"] { raven.CaptureErrorAndWait(errors.New("multiple patients inproperly matched"), nil) api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"}) return } if details != nil { details.(map[string]interface{})["test-results"] = labPatient.(map[string]interface{})["test-results"] } replaced = true break } } } else { // Previous version details.(map[string]interface{})["test-results"] = labDecoded["result"].(map[string]interface{})["patients"] replaced = true } if !replaced { log.Println("Failed to match Epic lab service patient to mobile patient") raven.CaptureErrorAndWait(errors.New("Failed to match Epic lab service patient to mobile patient"), nil) api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message": "Interal Error"}) return } } api.Render(w, req, http.StatusOK, decoded) }
func ItemHandler(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) source := strings.ToLower(vars["source"]) id := vars["id"] bloomConn := api.Conn() searchConn := bloomConn.SearchConnection() if !validElasticSearchRegexp.MatchString(source) { api.Render(w, req, http.StatusNotFound, "item not found") return } if !validElasticSearchRegexp.MatchString(id) { api.Render(w, req, http.StatusNotFound, "item not found") return } apiKey, ok := context.Get(req, "api_key").(string) if !ok { apiKey = "" } _, ok, err := bloomConn.SearchTypeWithNameAndKey(source, apiKey) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } if !ok { api.Render(w, req, 404, map[string]string{ "name": "Source Not Found", "message": "Please contact [email protected] if this is in error", }) return } if apiKey == "" { api.AddMessage(req, "Warning: Use of the dataset, '"+source+"', without an API key is for development-use only. Use of this API without a key without an API key is for development-use only. Use of this API without a key is rate-limited. For hosted, production access, please email '*****@*****.**' for an API key.") } result, err := searchConn.Get(source, "main", id, nil) if err != nil && err.Error() == elastigo.RecordNotFound.Error() { api.Render(w, req, http.StatusNotFound, "item not found") return } else if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } var found map[string]interface{} err = json.Unmarshal(*result.Source, &found) if err != nil { log.Println(err) api.Render(w, req, http.StatusInternalServerError, "Internal Server Error") return } body := map[string]interface{}{"result": found} api.AddFeature(req, "handler:item") api.AddFeature(req, source) api.Render(w, req, http.StatusOK, body) return }