Search code examples
http-postprometheuspromqlhttpapi

Prometheus HTTP API - POST Request


We are working with Prometheus HTTP API, and we're sending GET requests to the following endpoint:

/api/v1/query

At the beginning things worked as expected, but recently when our queries got bigger, request-URI became too large.

Docs says that it is possible to send POST request to the same endpoint, and pass the query parameter directly in the request body, instead of passing a query param as part of the URL..

This should solve our problem, but I couldn't find any example or guidelines explaining how to do it.

URL query length is limited, so we are looking for a way to send the query as part of the body :

End-point : http://server:8082/api/v1/query

Body :

{
    "query": "count(count(node_cpu_seconds_total{instance=~\"iServer.*\",job=\"events_prometheus\"}) by (cpu))"
}

Response Error :

{
    "status": "error",
    "errorType": "bad_data",
    "error": "invalid parameter 'query': parse error at char 1: no expression found in input"
}

Just to mention that sending the same query, as a query param, will work and give us the expected results.


Solution

  • You can URL-encode these parameters directly in the request body by using the POST method and Content-Type: application/x-www-form-urlencoded header. This is useful when specifying a large query that may breach server-side URL character limits. If you use some programming language, you should build these requests like in the example below.

    Example code in golang:

    func main() {
        formData := url.Values{
            "query": {"sum(temperature) by(status)"},
            "time":  {"1670859244"},
        }
    
        client := &http.Client{}
    
        req, err := http.NewRequest("POST", "http://localhost:8428/api/v1/query", strings.NewReader(formData.Encode()))
        if err != nil {
            log.Fatalln(err)
        }
    
        req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    
        resp, err := client.Do(req)
        if err != nil {
            log.Fatalln(err)
        }
        defer resp.Body.Close()
    
        body, err := io.ReadAll(resp.Body)
        if err != nil {
            log.Fatalln(err)
        }
    
        log.Println(string(body))
    }
    

    In the response, you should see something like this.

    {"status":"success","data":{"resultType":"vector","result":[]}}
    

    But in the result, there should be some vector with data. An example of the response can check here https://docs.victoriametrics.com/keyConcepts.html#range-query