Пример #1
0
func Search(sourceType string, params *SearchParams, r *http.Request) (map[string]interface{}, error) {
	conn := api.Conn().SearchConnection()

	if sourceType != "usgov.hhs.npi" {
		api.AddMessage(r, "Warning: Use of the dataset, '"+sourceType+"', 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(r, "Warning: This query used the experimental dataset, '"+sourceType+"'. To ensure you're notified in case breaking changes need to be made, email [email protected] and ask for an API key.")
	}

	matches := phraseMatches(params.paramSets, r)

	query := map[string]interface{}{
		"from": params.Offset,
		"size": params.Limit,
		"query": map[string]interface{}{
			"bool": map[string]interface{}{
				"must": matches,
			},
		},
	}

	result, err := conn.Search("source", sourceType, nil, query)
	if err != nil {
		switch terr := err.(type) {
		case elastigo.ESError:
			if esTypeExceptionRegex.MatchString(terr.What) {
				return nil, api.NewParamsError("one or more values were of an unexpected type", map[string]string{})
			} else {
				return nil, err
			}
		default:
			return nil, err
		}
	}

	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
	}

	cleanedResult := map[string]interface{}{
		"meta": map[string]interface{}{
			"rowCount": result.Hits.Total,
		},
		"result": hits,
	}

	return cleanedResult, nil
}
Пример #2
0
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
}
Пример #3
0
func phraseMatches(paramSets []*SearchParamSet, r *http.Request) []interface{} {
	apiKey, ok := context.Get(r, "api_key").(string)
	if !ok {
		apiKey = ""
	}

	elasticPhrases := make([]interface{}, len(paramSets))
	for index, set := range paramSets {
		shouldValues := make([]map[string]interface{}, len(set.Values))
		api.AddFeature(r, "op:"+set.Op)
		for vIndex, value := range set.Values {
			switch set.Op {
			case "eq":
				shouldValues[vIndex] = map[string]interface{}{
					"match_phrase": map[string]interface{}{
						set.Key: value,
					},
				}
			case "fuzzy":
				if apiKey == "" {
					api.AddMessage(r, fmt.Sprintf(experimentalOperationMessageWithoutKey, "fuzzy"))
				} else {
					api.AddMessage(r, fmt.Sprintf(experimentalOperationMessage, "fuzzy"))
				}

				shouldValues[vIndex] = map[string]interface{}{
					"fuzzy": map[string]interface{}{
						set.Key: value,
					},
				}
			case "prefix":
				if apiKey == "" {
					api.AddMessage(r, fmt.Sprintf(experimentalOperationMessageWithoutKey, "prefix"))
				} else {
					api.AddMessage(r, fmt.Sprintf(experimentalOperationMessage, "prefix"))
				}
				shouldValues[vIndex] = map[string]interface{}{
					"prefix": map[string]interface{}{
						set.Key: strings.ToLower(value),
					},
				}
			case "gte":
				shouldValues[vIndex] = map[string]interface{}{
					"range": map[string]interface{}{
						set.Key: map[string]interface{}{
							"gte": value,
						},
					},
				}
			case "gt":
				shouldValues[vIndex] = map[string]interface{}{
					"range": map[string]interface{}{
						set.Key: map[string]interface{}{
							"gt": value,
						},
					},
				}
			case "lte":
				shouldValues[vIndex] = map[string]interface{}{
					"range": map[string]interface{}{
						set.Key: map[string]interface{}{
							"lte": value,
						},
					},
				}
			case "lt":
				shouldValues[vIndex] = map[string]interface{}{
					"range": map[string]interface{}{
						set.Key: map[string]interface{}{
							"lt": value,
						},
					},
				}
			}
		}

		elasticPhrases[index] = map[string]interface{}{
			"bool": map[string]interface{}{
				"should": shouldValues,
			},
		}
	}

	return elasticPhrases
}
Пример #4
0
func Search(sourceType string, params *SearchParams, r *http.Request) (map[string]interface{}, error) {
	conn := api.Conn().SearchConnection()

	apiKey, ok := context.Get(r, "api_key").(string)
	if !ok {
		apiKey = ""
	}

	if apiKey == "" {
		api.AddMessage(r, "Warning: Use of the dataset, '"+sourceType+"', 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.")
	}

	matches := phraseMatches(params.paramSets, r)

	var order = "asc"
	if params.Order != "" {
		order = params.Order
	}

	query := map[string]interface{}{
		"from": params.Offset,
		"size": params.Limit,
		"query": map[string]interface{}{
			"bool": map[string]interface{}{
				"must": matches,
			},
		},
	}

	if params.Sort != "" {
		if _, ok := context.Get(r, "api_key").(string); !ok {
			return nil, api.NewParamsError("'sort' is unsupported without a BloomAPI user account", map[string]string{})
		}

		query["sort"] = map[string]interface{}{
			params.Sort: map[string]interface{}{
				"order": order,
			},
		}

		api.AddFeature(r, "sort")
		api.AddMessage(r, experimentalSort)
	}

	result, err := conn.Search(sourceType, "main", nil, query)
	if err != nil {
		switch terr := err.(type) {
		case elastigo.ESError:
			if esTypeExceptionRegex.MatchString(terr.What) {
				return nil, api.NewParamsError("one or more values were of an unexpected type", map[string]string{})
			} else {
				return nil, err
			}
		default:
			return nil, err
		}
	}

	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
	}

	cleanedResult := map[string]interface{}{
		"meta": map[string]interface{}{
			"rowCount": result.Hits.Total,
		},
		"result": hits,
	}

	return cleanedResult, nil
}
Пример #5
0
func phraseMatches(paramSets []*SearchParamSet, r *http.Request) []interface{} {
	elasticPhrases := make([]interface{}, len(paramSets))
	for index, set := range paramSets {
		shouldValues := make([]map[string]interface{}, len(set.Values))
		for vIndex, value := range set.Values {
			switch set.Op {
			case "eq":
				shouldValues[vIndex] = map[string]interface{}{
					"match_phrase": map[string]interface{}{
						set.Key: value,
					},
				}
			case "fuzzy":
				api.AddMessage(r, fmt.Sprintf(experimentalOperationMessage, "fuzzy"))
				shouldValues[vIndex] = map[string]interface{}{
					"fuzzy": map[string]interface{}{
						set.Key: value,
					},
				}
			case "prefix":
				api.AddMessage(r, fmt.Sprintf(experimentalOperationMessage, "prefix"))
				shouldValues[vIndex] = map[string]interface{}{
					"prefix": map[string]interface{}{
						set.Key: value,
					},
				}
			case "gte":
				shouldValues[vIndex] = map[string]interface{}{
					"range": map[string]interface{}{
						set.Key: map[string]interface{}{
							"gte": value,
						},
					},
				}
			case "gt":
				shouldValues[vIndex] = map[string]interface{}{
					"range": map[string]interface{}{
						set.Key: map[string]interface{}{
							"gt": value,
						},
					},
				}
			case "lte":
				shouldValues[vIndex] = map[string]interface{}{
					"range": map[string]interface{}{
						set.Key: map[string]interface{}{
							"lte": value,
						},
					},
				}
			case "lt":
				shouldValues[vIndex] = map[string]interface{}{
					"range": map[string]interface{}{
						set.Key: map[string]interface{}{
							"lt": value,
						},
					},
				}
			}
		}

		elasticPhrases[index] = map[string]interface{}{
			"bool": map[string]interface{}{
				"should": shouldValues,
			},
		}
	}

	return elasticPhrases
}
Пример #6
0
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
}