Can not send my dashboard to Grafana via API

Hi guys,

I am trying to uload the following to my Grafana localhost:

{
“annotations”: {
“list”: [
{
“builtIn”: 1,
“datasource”: {
“type”: “grafana”,
“uid”: “-- Grafana --”
},
“enable”: true,
“hide”: true,
“iconColor”: “rgba(0, 211, 255, 1)”,
“name”: “Annotations & Alerts”,
“type”: “dashboard”
}
]
},
“editable”: true,
“fiscalYearStartMonth”: 0,
“graphTooltip”: 0,
“id”: 20,
“links”: ,
“liveNow”: false,
“panels”: ,
“refresh”: “5s”,
“schemaVersion”: 37,
“style”: “dark”,
“tags”: [
“templated”
],
“templating”: {
“list”:
},
“time”: {
“from”: “now-6h”,
“to”: “now”
},
“timepicker”: {},
“timezone”: “browser”,
“title”: “Pro”,
“uid”: “_FvW53pVk”,
“version”: 1,
“weekStart”: “”
}
(The is actually “[” and “]” with no space in between. I don’t know why they look like a squre here)

But I get an error, and I don’t have a clue what the problem could be.
I keep getting a 400 bad request error. The version of my Grafana is 9.3.2 and I am using Windows 10.

Unable to remotely see the error or the api code you are using on your computer :wink:

You are right. I forgot to provide furthur information about the error. Here is a picture in Insomnia(An API Design tool) and my json code on the left side and the message I recieve on the right side:



If you need more clarification, please let me know.

Is this different than following?

https://community.grafana.com/t/400-bad-request-response-while-uploading-json-files-via-http-api/78969

it is connected to my problem.

Have you read the docu about required data u need to send to api?

yes, now it seems better. I modiefied some lines in the code. Now Insomnia dosen’t parse a 400 error. It says OK200. That’s nice. Now the problem is that I have written a python code to upload the dashboard programattically:

import requests

# Set the API endpoint URL
api_url = "http://grafana.staged-by-discourse.com/api/dashboards/db"

# Set the authorization header
headers = {"Authorization": "Bearer  xxx"}

# Read the JSON file
with open("C:/Users/U765123/Downloads/grafonnet-lib-master/examples/dashboard_einfach.json", "r") as f:
    dashboard_json = f.read()

# Set the payload
payload = {"dashboard": dashboard_json, "overwrite": True}

# Send the POST request
response = requests.post(api_url, json=payload, headers=headers)

# Check the response status code
if response.status_code == 200:
    print("Successfully uploaded dashboard")
else:
    print("Failed to upload dashboard", response)
    print(response.json())

And this gives me the following error:

Failed to upload dashboard <Response [400]>
{'message': 'Dashboard title cannot be empty', 'status': 'empty-name'}

But my dashboard already has a title, so I don’t understand what the problem is…

And btw, this is now a dashboard example that works in Insomnia:

{
   "__inputs": [ ],
   "__requires": [ ],
	"dashboard": {
	
   "editable": false,
   "gnetId": null,
   "graphTooltip": 0,
   "hideControls": false,
   "id": null,
   "links": [ ],
   "refresh": "",
   "rows": [ ],
   "schemaVersion": 14,
   "style": "dark",
		   "tags": [ ],
   "templating": {
      "list": [ ]
   },
   "time": {
      "from": "now-6h",
      "to": "now"
   },
   "timepicker": {
      "refresh_intervals": [
         "5s",
         "10s",
         "30s",
         "1m",
         "5m",
         "15m",
         "30m",
         "1h",
         "2h",
         "1d"
      ],
      "time_options": [
         "5m",
         "15m",
         "1h",
         "6h",
         "12h",
         "24h",
         "2d",
         "7d",
         "30d"
      ]
	 },

   "timezone": "browser",
   "title": "E",
   "version": 0
	}
}

1 Like

I imported this last json into my grafana (via import grafana) and it does not work.

Again, we do not have access to your computer so we cant see what is in

C:/Users/U765123/Downloads/grafonnet-lib-master/examples/dashboard_einfach.json

this the script in the path:

{
   "__inputs": [ ],
   "__requires": [ ],
	"dashboard": {
	
   "editable": false,
   "gnetId": null,
   "graphTooltip": 0,
   "hideControls": false,
   "id": null,
   "links": [ ],
   "refresh": "",
   "rows": [ ],
   "schemaVersion": 14,
   "style": "dark",
		   "tags": [ ],
   "templating": {
      "list": [ ]
   },
   "time": {
      "from": "now-6h",
      "to": "now"
   },
   "timepicker": {
      "refresh_intervals": [
         "5s",
         "10s",
         "30s",
         "1m",
         "5m",
         "15m",
         "30m",
         "1h",
         "2h",
         "1d"
      ],
      "time_options": [
         "5m",
         "15m",
         "1h",
         "6h",
         "12h",
         "24h",
         "2d",
         "7d",
         "30d"
      ]
	 },

   "timezone": "browser",
   "title": "E",
   "version": 0
	}
}

But I also checked now. It dosen’t work for me either

1 Like

Hi @yosiasz and @mahiyouu

I had to twitch a couple things but it works for me.

At script level, I simply assigned the read json to the variable payload like so: (I guess it is not necessary to pass the payload in key-value pair format {"dashboard": dashboard_json,} when using the requests.request method

# Set the payload
payload = dashboard_json

My python script (named it script.py)

import requests

# Read the JSON file
with open(r"C:\Users\anton\Desktop\python\forum\body2.json", "r") as f:
    dashboard_json = f.read()

# Set the payload
payload = dashboard_json

url = "http://grafana.staged-by-discourse.com/api/dashboards/db"

headers = {
  'Accept': 'application/json',
  'Content-Type': 'application/json',
  'Authorization': 'Bearer xxx'
}

response = requests.request("POST", url, headers=headers, data=payload)

print(response.text)

The payload: (that is my body2.json file referenced at line 4 in script.py)

{
   "__inputs": [ ],
   "__requires": [ ],
	"dashboard": {

   "editable": false,
   "gnetId": null,
   "graphTooltip": 0,
   "hideControls": false,
   "id": null,
   "links": [ ],
   "refresh": "",
   "rows": [ ],
   "schemaVersion": 14,
   "style": "dark",
		   "tags": [ ],
   "templating": {
      "list": [ ]
   },
   "time": {
      "from": "now-6h",
      "to": "now"
   },
   "timepicker": {
      "refresh_intervals": [
         "5s",
         "10s",
         "30s",
         "1m",
         "5m",
         "15m",
         "30m",
         "1h",
         "2h",
         "1d"
      ],
      "time_options": [
         "5m",
         "15m",
         "1h",
         "6h",
         "12h",
         "24h",
         "2d",
         "7d",
         "30d"
      ]
	 },

   "timezone": "browser",
   "title": "Made via Python!",
   "version": 0
	}
}

Command in Anaconda prompt:

Result In Grafana (got an empty dashboard but it worked!)

1 Like

@antonio nice!

What happens when you open the dashboard?

yes, I also solved the problem in a similar way. Thank you!

1 Like

I also wrote a Python script that should create, delete and update existing dashboards:

import json
import requests
import subprocess

# Set the base URL of your Grafana instance and your API key
GRAFANA_URL = "http://grafana.staged-by-discourse.com"
API_KEY = "xxx"

def create_dashboard(dashboard_json):
    # Use the Grafana API to create a new dashboard
    url = f"http://grafana.staged-by-discourse.com/api/dashboards/db"
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    }
    # Set the payload
    payload = {"dashboard": dashboard_json, "overwrite": True}

    # Send the API request to create the dashboard
    response = requests.post(url, headers=headers, json=payload)

    #response = requests.post(url, headers=headers, json=dashboard_json)
    if response.status_code != 200:
        raise Exception(f"Failed to create dashboard: {response.text}")

def update_dashboard(dashboard_id, dashboard_json):
    # Use the Grafana API to update an existing dashboard
    #url = f"{GRAFANA_URL}/d/{dashboard_id}"
    url = f'{GRAFANA_URL}/api/dashboards/db/{dashboard_id}'
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    }
    response = requests.patch(url, headers=headers, json=dashboard_json)
    if response.status_code != 200:
        raise Exception(f"Failed to update dashboard: {response.text}")

def delete_dashboard(dashboard_id):
    # Use the Grafana API to delete an existing dashboard
    #url = f"{GRAFANA_URL}/api/dashboards/id/{dashboard_id}"
    url = f"{GRAFANA_URL}/dashboards/{dashboard_id}"
    headers = {
        "Authorization": f"Bearer {API_KEY}",
    }
    response = requests.delete(url, headers=headers)
    if response.status_code != 200:
        raise Exception(f"Failed to delete dashboard: {response.text}")

#if __name__ == "__name__":
    # Ask the user for the path to their jsonnet file
jsonnet_path = input("Enter the path to your jsonnet file: ")

# Convert the jsonnet file to JSON using the jsonnet command-line tool
#dashboard_json = json.loads(subprocess.run(["jsonnet", jsonnet_path], capture_output=True).stdout)

#Run the Jsonnet command  to convert Jsonnet to JSON
process = subprocess.run(['jsonnet', jsonnet_path], stdout=subprocess.PIPE)
json_str = process.stdout.decode('utf-8')

#Printing out the JSON file
print(json_str)

#Parse the JSON string into a Python dictionary
dashboard_json = json.loads(json_str)

# Ask the user what they want to do with the dashboard
action = input("What do you want to do with the dashboard? (create/modify/delete): ")

if action == "create":
    # Create the dashboard
    create_dashboard(dashboard_json)
    print("Dashboard created successfully")
elif action == "modify":
    # Modify the dashboard
    dashboard_id = input("Enter the ID of the dashboard you want to modify: ")
    update_dashboard(dashboard_id, dashboard_json)
    print("Dashboard modified successfully")
elif action == "delete":
    # Delete the dashboard
    dashboard_id = input("Enter the ID of the dashboard you want to delete: ")
    delete_dashboard(dashboard_id)
    print("Dashboard deleted successfully")
else:
    print("Invalid action")

creating dashboards works easily here. But whenever I want to delete or update an existing dashboard and put in the dashboard id, it parses an error:

What do you want to do with the dashboard? type 'c' for create, 'm' for modify nad 'd' for delete): m
Enter the ID of the dashboard you want to modify: cQl0Oih4z
Traceback (most recent call last):
 File "C:\Users\U765123\Downloads\grafonnet-lib-master\examples\python_scripts\upload_files_actions.py", line 75, in <module>
    update_dashboard(dashboard_id, dashboard_json)
  File "C:\Users\U765123\Downloads\grafonnet-lib-master\examples\python_scripts\upload_files_actions.py", line 36, in update_dashboard
    raise Exception(f"Failed to update dashboard: {response.text}")
Exception: Failed to update dashboard: {"message":"Not found"}

And I dont know how to solve this. I am using microsoft edge for my localhost.
I asume something is wrong with the url, but I dont know what url to put in there.
This is the url of when I am on the dashboard in Grafana.

nice script @mahiyouu !

To call the delete endpoint, the url format should follow this structure :

/api/dashboards/uid/:uid,

However, the url your delete function is posting is

url = f"{GRAFANA_URL}/dashboards/{dashboard_id}".

It seems to be missing part of the URL (the /uid/ part of the path).

1 Like

Oh thanks for asking. :slight_smile: Well, nothing happens. But I guess it was because I sent a pretty much empty dashboard.

I just tried to send another dashboard, one of mine, and it did work perfect. I just needed to get the JSON of the dashboard, and wrap the whole body up inside this: :+1:

{

"dashboard":

 }

2 Likes

@antonio Here I modified my code a little bit:

import json
import requests
import subprocess

# Set the base URL of your Grafana instance and your API key
GRAFANA_URL = "http://grafana.staged-by-discourse.com"
API_KEY = "XXX"

def create_dashboard(dashboard_json):
    # Use the Grafana API to create a new dashboard
    url = f"http://grafana.staged-by-discourse.com/api/dashboards/db"
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    }
    # Set the payload
    payload = {"dashboard": dashboard_json, "overwrite": True}

    # Send the API request to create the dashboard
    response = requests.post(url, headers=headers, json=payload)
    

    #response = requests.post(url, headers=headers, json=dashboard_json)
    if response.status_code != 200:
        raise Exception(f"Failed to create dashboard: {response.text}")

def update_dashboard(dashboard_id, dashboard_json):
    # Use the Grafana API to update an existing dashboard
    url = f'{GRAFANA_URL}/api/dashboards/uid/{dashboard_id}'
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
        "Accept": "application/json"
    }

    # Send the API request to create the dashboard
    #response = requests.post(url=url, headers=headers, verify=False)
    response = requests.patch(url, headers=headers, json=dashboard_json)

    
    if response.status_code != 200:
        raise Exception(f"Failed to update dashboard: {response.text}")

def delete_dashboard(dashboard_id):
    # Use the Grafana API to delete an existing dashboard
    url = f"{GRAFANA_URL}/api/dashboards/uid/{dashboard_id}"
    #url = f"{GRAFANA_URL}/dashboards/{dashboard_id}"
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
        "Accept": "application/json"
    }
    response = requests.delete(url = url, headers=headers, verify=False)
    if response.status_code != 200:
        raise Exception(f"Failed to delete dashboard: {response.text}")

# Ask the user for the path to their jsonnet file
jsonnet_path = input("Enter the path to your jsonnet file: ")

# Convert the jsonnet file to JSON using the jsonnet command-line tool
#dashboard_json = json.loads(subprocess.run(["jsonnet", jsonnet_path], capture_output=True).stdout)

#Run the Jsonnet command  to convert Jsonnet to JSON
process = subprocess.run(['jsonnet', jsonnet_path], stdout=subprocess.PIPE)
json_str = process.stdout.decode('utf-8')

#Printing out the JSON file
print(json_str)

#Parse the JSON string into a Python dictionary
dashboard_json = json.loads(json_str)

# Ask the user what they want to do with the dashboard
action = input("What do you want to do with the dashboard? type 'c' for create, 'm' for modify and 'd' for delete): ")

if action == "c":
    # Create the dashboard
    create_dashboard(dashboard_json)
    print("Dashboard created successfully")
elif action == "m":
    # Modify the dashboard
    dashboard_id = input("Enter the ID of the dashboard you want to modify: ")
    update_dashboard(dashboard_id, dashboard_json)
    print("Dashboard modified successfully")
elif action == "d":
    # Delete the dashboard
    dashboard_id = input("Enter the ID of the dashboard you want to delete: ")
    delete_dashboard(dashboard_id)
    print("Dashboard deleted successfully")
else:
    print("Invalid action")

now I have the problem that I cant modify my dashboards. Deleting and creating dashboards work: Here is the error:

What do you want to do with the dashboard? type 'c' for create, 'm' for modify and 'd' for delete): m
Enter the ID of the dashboard you want to modify: 7Yq62Z24k
Traceback (most recent call last):
  File "C:\Users\U765123\Downloads\grafonnet-lib-master\examples\python_scripts\upload_files_actions.py", line 83, in <module>
    update_dashboard(dashboard_id, dashboard_json)
  File "C:\Users\U765123\Downloads\grafonnet-lib-master\examples\python_scripts\upload_files_actions.py", line 42, in update_dashboard
    raise Exception(f"Failed to update dashboard: {response.text}")
Exception: Failed to update dashboard: {"message":"Not found"}

so what is my mistake there?

the docs say that to create/update dashboards you just need /api/dashboards/db

But this is not all though, you will need to also increment the dashboard version by including the attribute: "version": xx, in your dashboard JSON body, or you will get another error "The dashboard has been changed by someone else","status":"version-mismatch"