Create Meraki Admin with Web Form

Overview

This flow provides a demonstration of using the Meraki Dashboard API with Node-RED. It will display a simple webform and send the details to Meraki using the API. This concept can also be used for any of the other API calls available.

screenshot

Setup

Update the function node labelled "Env Variables: UPDATE THIS" with your Meraki API key, your organization ID and shard number.

  • Meraki API Key Meraki Dashboard --> Organization --> Settings --> Enable API Meraki Dashboard --> Profile --> Generate Key
  • Your Shard number is the prefix to the normal Dashboard.meraki.com website. You will notice that once you login, a number will prefix the meraki.com domain. This is your "shard" number and indicates which servers your organization resides on. Because some API calls do not like this redirect, its best to just hard code the number if the orgs share a shard. https://n123.dashboard.meraki.com n123 is the shard number. Enter that in your variables.

Create an Admin Account

This demo flow will create an Organizational administrator.

It will first do a 'get' request to Meraki and pull a listing of all organizations, which includes their names and ID.

The form then asks for the name, email and permission access (full or read-only). Once submitted, the flow sends a 'post' request to Meraki to create the account. If successful, the screen will update with the details of the new user as a confirmation. If there are errors, they will appear as well (although not formatted at this time).

API Documentation

developers.meraki.com

Written by

Cory Guynn 2017

www.InternetOfLEGO.com

[
    {
        "id": "c81f2449.80d548",
        "type": "inject",
        "z": "1f491da9.9d14e2",
        "name": "Create Admin",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "repeat": "",
        "crontab": "",
        "once": false,
        "x": 110,
        "y": 460,
        "wires": [
            [
                "5759b718.53c9c8"
            ]
        ]
    },
    {
        "id": "f061c93f.1f4488",
        "type": "http request",
        "z": "1f491da9.9d14e2",
        "name": "",
        "method": "use",
        "ret": "obj",
        "url": "",
        "tls": "",
        "x": 801.1110725402832,
        "y": 528.8888740539551,
        "wires": [
            [
                "7f4329cf.7c4928",
                "ea013c.9cbf6ec8"
            ]
        ]
    },
    {
        "id": "7f4329cf.7c4928",
        "type": "debug",
        "z": "1f491da9.9d14e2",
        "name": "Create Meraki Admin",
        "active": true,
        "console": "false",
        "complete": "payload",
        "x": 830.0000152587891,
        "y": 571.1111135482788,
        "wires": []
    },
    {
        "id": "c6e83f8f.caf",
        "type": "http in",
        "z": "1f491da9.9d14e2",
        "name": "",
        "url": "/meraki/admins",
        "method": "get",
        "swaggerDoc": "",
        "x": 110,
        "y": 220,
        "wires": [
            [
                "cdf5a50a.f0c008"
            ]
        ]
    },
    {
        "id": "cdf5a50a.f0c008",
        "type": "function",
        "z": "1f491da9.9d14e2",
        "name": "msg.url = \"/meraki/newAdmin\";",
        "func": "msg.url = \"/meraki/newAdmin\";\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 410,
        "y": 220,
        "wires": [
            [
                "211cf939.c8c066"
            ]
        ]
    },
    {
        "id": "90eec72b.dd9338",
        "type": "template",
        "z": "1f491da9.9d14e2",
        "name": "CSS",
        "field": "payload.style",
        "fieldType": "msg",
        "format": "css",
        "syntax": "mustache",
        "template": "input[type=text], select {\n    width: 100%;\n    padding: 12px 20px;\n    margin: 8px 0;\n    display: inline-block;\n    border: 1px solid #ccc;\n    border-radius: 4px;\n    box-sizing: border-box;\n}\n\ninput[type=email], select {\n    width: 100%;\n    padding: 12px 20px;\n    margin: 8px 0;\n    display: inline-block;\n    border: 1px solid #ccc;\n    border-radius: 4px;\n    box-sizing: border-box;\n}\n\ninput[type=submit] {\n    width: 50%;\n    background-color: #4CAF50;\n    color: white;\n    padding: 14px 20px;\n    margin: 8px 0;\n    border: none;\n    border-radius: 4px;\n    cursor: pointer;\n}\n\ninput[type=submit]:hover {\n    background-color: #45a049;\n}\n\ndiv form {\n    border-radius: 5px;\n    background-color: #f2f2f2;\n    padding: 20px;\n}\n\n.adminform {\n    width: 90%;\n}\n",
        "x": 330,
        "y": 300,
        "wires": [
            [
                "60302eb5.4352b"
            ]
        ]
    },
    {
        "id": "211cf939.c8c066",
        "type": "template",
        "z": "1f491da9.9d14e2",
        "name": "JavaScript",
        "field": "payload.script",
        "fieldType": "msg",
        "format": "javascript",
        "syntax": "mustache",
        "template": "\n$(document).ready(function(e) {\n    \n    \n    $.ajax({\n        url: 'api/organizations',\n        type: 'get',\n        datatype: 'json',\n        success: function(data){\n            var toAppend = '';\n            //if(typeof data === 'object'){\n                for(var i=0;i<data.length;i++){\n                    toAppend += '<option value='+data[i][\"id\"]+'>'+data[i]['name']+'</option>';\n                }\n            //}\n            console.log(\"orgs toAppend\",toAppend);\n            $('#orgs').append(toAppend);\n        }\n    });\n    \n    $(\"form[ajax=true]\").submit(function(e) {\n        \n        e.preventDefault();\n        \n        var form_data = $(this).serialize();\n        var form_url = $(this).attr(\"action\");\n        var form_method = $(this).attr(\"method\").toUpperCase();\n        \n        var orgId = $(\"#orgs\").val();\n        \n        $(\"#loadingimg\").show();\n        \n        $.ajax({\n            url: form_url+\"/\"+orgId, \n            type: form_method,       \n            data: form_data,     \n            cache: false,\n            success: function(data){\n                \n                // Create simple HTML response\n                var response = \n                    \"<div>\"+\n                        \"<h2>Created Admin!</h2>\"+\n                        \"<h4>Name</h4><p>\"+data.name+\"</p>\"+\n                        \"<h4>E-Mail</h4><p>\"+data.email+\"</p>\"+\n                        \"<h4>ID</h4><p>\"+data.id+\"</p>\"+\n                        \"<h4>Tags</h4><p>\"+data.tags+\"</p>\"+\n                        \"<h4>Org Access</h4><p>\"+data.orgAccess+\"</p>\"+\n                    \"</div>\";\n                \n                console.log(\"response: \"+JSON.stringify(data));\n                \n                \n                $(\"#result\").html(response); \n                \n                $(\"#loadingimg\").hide();\n                $( '#createadmin' ).each(function(){\n                    this.reset();\n                });\n            },\n            error: function(error){\n                $(\"#result\").html(error.responseText);\n            }\n        });    \n        \n    });\n    \n});",
        "x": 350,
        "y": 260,
        "wires": [
            [
                "90eec72b.dd9338"
            ]
        ]
    },
    {
        "id": "fe67769b.ba37b8",
        "type": "comment",
        "z": "1f491da9.9d14e2",
        "name": "Create Admin Form",
        "info": "",
        "x": 110,
        "y": 140,
        "wires": []
    },
    {
        "id": "3ec4833d.ec3b7c",
        "type": "comment",
        "z": "1f491da9.9d14e2",
        "name": "Form Submission URL",
        "info": "",
        "x": 400,
        "y": 180,
        "wires": []
    },
    {
        "id": "be2485f7.33ddc8",
        "type": "http response",
        "z": "1f491da9.9d14e2",
        "name": "",
        "x": 670,
        "y": 220,
        "wires": []
    },
    {
        "id": "60302eb5.4352b",
        "type": "template",
        "z": "1f491da9.9d14e2",
        "name": "HTML",
        "field": "payload",
        "fieldType": "msg",
        "format": "handlebars",
        "syntax": "mustache",
        "template": "<html>\n  <head>\n    <title>Meraki Dasbhoard API - Admin User</title>\n    <meta name=\"viewport\" content=\"initial-scale=1.0, user-scalable=no\">\n    <meta charset=\"utf-8\">\n    <!--\n    <script src=\"http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js\"></script>\n    -->\n    <script\n      src=\"https://code.jquery.com/jquery-3.2.1.min.js\"\n      integrity=\"sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=\"\n      crossorigin=\"anonymous\"></script>\n      \n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u\" crossorigin=\"anonymous\">  \n    <script>{{{payload.jquery}}}</script>\n    <style>{{{payload.style}}}</style>\n  </head>\n  \n<div class=\"container\">\n    <h2>Create a Meraki Dashboard Administrator</h2>\n    <h4><a href=\"http://developers.meraki.com\">Meraki Developers Portal</a></h4>\n\n<div class=\"col-md-6\">\n<div class=\"adminform\">\n  <form id=\"createadmin\" method=\"post\" action=\"{{url}}\" ajax=\"true\">\n    <select id=\"orgs\" name=\"orgs\">\n        <option>Select Organization..</option>\n    </select>\n    <label>Contact Details</label>\n    <input type=\"text\" id=\"fname\" name=\"firstname\" placeholder=\"First Name\" required=true/>\n    <input type=\"text\" id=\"lname\" name=\"lastname\" placeholder=\"Last Name\" required=true/>\n    <input type=\"email\" id=\"email\" name=\"email\" placeholder=\"E-mail\" required=true/>\n    <br>\n\n    <label>Organization Permissions</label>\n    <select id=\"orgAccess\" name=\"orgAccess\" placeholder=\"Org Access\">\n      <option value=\"full\">full</option>\n      <option value=\"read-only\">read-only</option>\n    </select>\n    \n  \n    <input type=\"submit\" class=\"button\" value=\"Submit\">\n  </form>\n</div>\n</div>\n\n<div class=\"col-md-6\">\n    <span id=\"result\"></span>\n</div>\n</div>\n</body>\n</html>\n<script>{{{payload.script}}}</script>",
        "x": 330,
        "y": 340,
        "wires": [
            [
                "be2485f7.33ddc8"
            ]
        ]
    },
    {
        "id": "5759b718.53c9c8",
        "type": "function",
        "z": "1f491da9.9d14e2",
        "name": "Sample Data",
        "func": "msg.payload = {\n    \"name\": \"NodeRED Test\",\n    \"email\": \"cory2@internetoflego.com\",\n    \"orgAccess\": \"full\"\n };\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 351.00001525878906,
        "y": 459.77778816223145,
        "wires": [
            [
                "54ae2286.028d2c"
            ]
        ]
    },
    {
        "id": "bb0b7d83.e29ba",
        "type": "http in",
        "z": "1f491da9.9d14e2",
        "name": "",
        "url": "/meraki/newAdmin/:orgId",
        "method": "post",
        "swaggerDoc": "",
        "x": 172.11111450195312,
        "y": 517.5555534362793,
        "wires": [
            [
                "8e63af69.effcf"
            ]
        ]
    },
    {
        "id": "ea013c.9cbf6ec8",
        "type": "http response",
        "z": "1f491da9.9d14e2",
        "name": "",
        "x": 987.6666259765625,
        "y": 468.6666679382324,
        "wires": []
    },
    {
        "id": "8e63af69.effcf",
        "type": "function",
        "z": "1f491da9.9d14e2",
        "name": "form data",
        "func": "// Convert form data into Meraki API expected JSON\nmsg.orgId = msg.req.params.orgId;\nmsg.payload = {\n    name: msg.req.body.firstname + \" \" + msg.req.body.lastname,\n    email: msg.req.body.email,\n    orgAccess: msg.req.body.orgAccess\n};\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 380,
        "y": 520,
        "wires": [
            [
                "9ca39021.41a2b",
                "54ae2286.028d2c"
            ]
        ]
    },
    {
        "id": "9ca39021.41a2b",
        "type": "debug",
        "z": "1f491da9.9d14e2",
        "name": "newAdmin Form Data",
        "active": true,
        "console": "false",
        "complete": "payload",
        "x": 296.5555725097656,
        "y": 558.6666631698608,
        "wires": []
    },
    {
        "id": "e50d6724.15b258",
        "type": "comment",
        "z": "1f491da9.9d14e2",
        "name": "Meraki Dashboard API Sample App",
        "info": "Create a Meraki Dasbhoard Admin with a form",
        "x": 459,
        "y": 24.000003814697266,
        "wires": []
    },
    {
        "id": "a5b4aa9b.c71de8",
        "type": "inject",
        "z": "1f491da9.9d14e2",
        "name": "List Organizations",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "repeat": "",
        "crontab": "",
        "once": false,
        "x": 130,
        "y": 660,
        "wires": [
            [
                "15632b8.22540d5"
            ]
        ]
    },
    {
        "id": "15632b8.22540d5",
        "type": "function",
        "z": "1f491da9.9d14e2",
        "name": "Meraki API - List Organizations",
        "func": "// Set Variables\nvar apiKey = global.get('apiKey');\n\n\n\n// API Call\nmsg.headers = {\n    \"X-Cisco-Meraki-API-Key\": apiKey\n};\n\nmsg.url = \"https://dashboard.meraki.com/api/v0/organizations\";\nmsg.method = 'get';\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 430,
        "y": 660,
        "wires": [
            [
                "23fdd666.9cf74a"
            ]
        ]
    },
    {
        "id": "23fdd666.9cf74a",
        "type": "http request",
        "z": "1f491da9.9d14e2",
        "name": "",
        "method": "use",
        "ret": "txt",
        "url": "",
        "tls": "",
        "x": 670,
        "y": 660,
        "wires": [
            [
                "d6109831.8ca3a8"
            ]
        ]
    },
    {
        "id": "d02830a3.34bfa",
        "type": "http in",
        "z": "1f491da9.9d14e2",
        "name": "",
        "url": "/meraki/api/organizations",
        "method": "get",
        "swaggerDoc": "",
        "x": 160,
        "y": 700,
        "wires": [
            [
                "15632b8.22540d5"
            ]
        ]
    },
    {
        "id": "d6109831.8ca3a8",
        "type": "function",
        "z": "1f491da9.9d14e2",
        "name": "Large Int Helper",
        "func": "const regex = /\"id\":(.*?)(?:,)/g;\nconst str = `{\"id\":351024,\"name\":\"Cisco Mini Demo 2\"},{\"id\":215332,\"name\":\"Cisco Mini Demo 1\"},`;\nlet m;\n\nwhile ((m = regex.exec(str)) !== null) {\n    // This is necessary to avoid infinite loops with zero-width matches\n    if (m.index === regex.lastIndex) {\n        regex.lastIndex++;\n    }\n    \n    // The result can be accessed through the `m`-variable.\n    m.forEach((match, groupIndex) => {\n        console.log(`Found match, group ${groupIndex}: ${match}`);\n    });\n}\n\n\nmsg.payload = msg.payload.replace(/\"id\":(.*?)(?:,)/g,\"\\\"id\\\"\\:\\\"$1\\\"\\,\");\nconsole.log(\"new json with regex replace \",msg.payload);\nreturn msg",
        "outputs": 1,
        "noerr": 0,
        "x": 860,
        "y": 660,
        "wires": [
            [
                "91f1eb0d.41a1e8"
            ]
        ]
    },
    {
        "id": "91f1eb0d.41a1e8",
        "type": "json",
        "z": "1f491da9.9d14e2",
        "name": "",
        "x": 1010,
        "y": 600,
        "wires": [
            [
                "4d7cb514.8d831c",
                "3d5b0708.b38a88"
            ]
        ]
    },
    {
        "id": "4d7cb514.8d831c",
        "type": "http response",
        "z": "1f491da9.9d14e2",
        "name": "",
        "x": 1150,
        "y": 620,
        "wires": []
    },
    {
        "id": "3d5b0708.b38a88",
        "type": "debug",
        "z": "1f491da9.9d14e2",
        "name": "List Orgs JSON",
        "active": true,
        "console": "false",
        "complete": "payload",
        "x": 1120,
        "y": 660,
        "wires": []
    },
    {
        "id": "760533bc.b8681c",
        "type": "inject",
        "z": "1f491da9.9d14e2",
        "name": "Sets Defaults - Injected at start",
        "topic": "",
        "payload": "Setting Environment Variables",
        "payloadType": "str",
        "repeat": "",
        "crontab": "",
        "once": true,
        "x": 170,
        "y": 60,
        "wires": [
            [
                "d6bf7874.d504f8"
            ]
        ]
    },
    {
        "id": "d6bf7874.d504f8",
        "type": "function",
        "z": "1f491da9.9d14e2",
        "name": "Env Variables: UPDATE THIS",
        "func": "//  ###### User Defined Variables ######\n\nconst API_KEY = 'yourAPIKey'; //Your API KEY (Keep this secret. Do not publish)\nvar shard = 'dashboard'; // https://n149.meraki.com , where n149 represent the shard number. This is defined to avoid redirect issues.\nvar orgId = ''; // Your default Organization ID\n\n\n\n\n\n// ###### Set and Get Global variables ######\n\n\n// Assign to Global Context \nglobal.set('apiKey', API_KEY); // pulling API key via \"secret\" node. This avoides publishing the API key when sharing the flow\nglobal.set('shard', shard);\n\nglobal.set('orgId', orgId);\n\n\nmsg.payload = \"settings set\";\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 440,
        "y": 60,
        "wires": [
            [
                "2bd4e773.77a128"
            ]
        ]
    },
    {
        "id": "2bd4e773.77a128",
        "type": "debug",
        "z": "1f491da9.9d14e2",
        "name": "Flow Env Variables",
        "active": true,
        "console": "false",
        "complete": "true",
        "x": 750,
        "y": 60,
        "wires": []
    },
    {
        "id": "54ae2286.028d2c",
        "type": "function",
        "z": "1f491da9.9d14e2",
        "name": "Meraki API - Create Admin",
        "func": "// Set Variables\nvar apiKey = global.get('apiKey');\nvar shard = global.get('shard');\n//var orgId = global.get('orgId'); // set via global variables\nvar orgId = msg.orgId; //set via request parameter\n\n// API Call\nmsg.headers = {\n    \"X-Cisco-Meraki-API-Key\": apiKey\n};\nmsg.url = \"https://\"+shard+\".meraki.com/api/v0/organizations/\"+orgId+\"/admins\";\nmsg.method = 'post';\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 591,
        "y": 495.99999618530273,
        "wires": [
            [
                "f061c93f.1f4488"
            ]
        ]
    },
    {
        "id": "878db1a6.ac677",
        "type": "comment",
        "z": "1f491da9.9d14e2",
        "name": "APIs",
        "info": "",
        "x": 70,
        "y": 400,
        "wires": []
    }
]
dexterlabora

Flow Info

created 2 months, 1 week ago

Node Types

Core
  • comment (x4)
  • debug (x4)
  • function (x7)
  • http in (x3)
  • http request (x2)
  • http response (x3)
  • inject (x3)
  • json (x1)
  • template (x3)

Tags

  • cisco
  • meraki
  • form
  • api
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option