Using the REST API with .Net

In common with all automatically created documentation, the REST API has plenty of detail, but no indication of how to use it.
Thanks to the wonders of Fiddler, I’ve been able to do some basic integration using C#. The actual UI of Metabase is all handled in the massive Javascript app in your browser, so don’t expect anything pretty from the API, this is much more about admin. That said, as many of the questions on the forum have been about things such as synchronising users and groups with other applications, there’s a lot of useful stuff in here.

Below are methods from a test page I was working on. I’m playing ‘pass the parcel’ with the security token for clarity. You’ll probably want to tidy it into a class variable. I’ve also hardcoded my server address. It should be in web.config.
One of the things I found awkward was passing values to JSON in the correct format. Simplest approach appears to be to create a dictionary then convert. As dictionaries can be different formats (typically <string, string> or <string, int>), it was easier to keep converting to JSON to pass around.
The other pain is passing the token to the request. That’s what

request.Headers.Add("X-Metabase-Session: " + token);`

is doing.
I’ve not done anything with DELETE, but looks pretty easy compared to the rest.

What I really want to do next is to pass the token to the main Metabase page, but that doesn’t appear to be possible yet.

I think to be up to date, I’m supposed to use HTTPClient rather than WebRequest and WebResponse, but there you go! If anyone feels strongly, I’d be very happy for them to post a conversion. Some error handling would be useful too!

First, before doing anything else, you need to get the security token:

   private string GetToken(string userName, string password)
         {
             //Can be reused for any POST
             WebRequest request = WebRequest.Create("http://jasperc:3000/api/session");
             var user = new Dictionary<string, string>();
             user.Add("username", userName);
             user.Add("password", password);
             string sr = JsonConvert.SerializeObject(user);
             request.Method = "POST";
             request.ContentType = "application/json";
             request.ContentLength = sr.Length;
             using (var writer = new StreamWriter(request.GetRequestStream()))
             {
                 writer.Write(sr);
             }
             WebResponse response = request.GetResponse();
             Stream dataStream = response.GetResponseStream();
             StreamReader reader = new StreamReader(dataStream);
             string serverResponse = reader.ReadToEnd();
             // clean up.
             reader.Close();
             dataStream.Close();
             response.Close();
             var id = JsonConvert.DeserializeObject<Dictionary<string, string>>(serverResponse);
             return id["id"];

Next, we can create a new user. This is done using a POST, so I created a separate more generic method to do the POST itself:

    private string CreateUser(string firstName, string lastName, string emailAddress, string password, string token)
        {//Creates the new user then returns their userId
        var user = new Dictionary<string, string>();
        user.Add("first_name", firstName);
        user.Add("last_name", lastName);
        user.Add("email", emailAddress);
        user.Add("password", password);
        string newUser = PostRequest("user/", JsonConvert.SerializeObject(user), token);
        var id = JsonConvert.DeserializeObject<Dictionary<string, string>>(newUser);
        return id["id"];
    }
    private string PostRequest(string api, string parameters, string token)
        {
            WebRequest request = WebRequest.Create("http://jasperc:3000/api/" + api);
            request.Method = "POST";
            request.Headers.Add("X-Metabase-Session: " + token);
            request.ContentType = "application/json";
            request.ContentLength = parameters.Length;
            using (var writer = new StreamWriter(request.GetRequestStream()))
            {
                writer.Write(parameters);
            }
            WebResponse response = request.GetResponse();
            Stream dataStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(dataStream);
            //returns the response as a JSON string including the id
            string serverResponse = reader.ReadToEnd();
            // clean up.
            reader.Close();
            dataStream.Close();
            response.Close();
            return serverResponse;
        }

In a similar fashion, I created a generic method for GET. As GET always seems to take parameters on the uri rather than in the body, it’s much simpler:

     private string GetResponse(string token, string apiCall)
        {
            WebRequest request = WebRequest.Create("http://jasperc:3000/api/" + apiCall);
            request.Method = "GET";
            request.ContentType = "application/json";
            request.Headers.Add("X-Metabase-Session: " + token);
            WebResponse response = request.GetResponse();
            Stream dataStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(dataStream);
            //returned as serialized JSON, need to convert if plan to use
            string serverResponse = reader.ReadToEnd();
            // clean up.
            reader.Close();
            dataStream.Close();
            response.Close();
            return serverResponse;
        }

Finally, bringing it all together, this method adds a user to a group using the name of the group. It really needs an extra bit to create the group if it doesn’t already exist rather than just returning 0. If there were 100s of groups, the foreach would need some attention too:

       private string AddUserToGroup(string newUserId, string groupName, string token)
        {
            string groupId = "0";
            //first find the group
            string groupList = GetResponse(token, "permissions/group");
            var groups = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(groupList);
            foreach (Dictionary <string, string> group in groups)
            {
                if (group["name"] ==groupName )
                {
                    //found the group, add the user
                    var membership = new Dictionary<string, int>();
                    membership.Add("group_id", int.Parse(group["id"]));
                    membership.Add("user_id", int.Parse(newUserId));
                    groupId = PostRequest("permissions/membership", JsonConvert.SerializeObject( membership), token);
                }
            }
            return groupId;
        }
1 Like

Sweet stuff @AndrewMBaines - I see you found the code formatting options with triple back-ticks ``` - or is it just due to indents? Seems to still be missing for your first codeblock

pro tip: Like described in https://discourse.stonehearth.net/t/discourse-guide-code-formatting/30587 you can even get .cs code highlighting like below:

``` cs
    private string GetToken(string userName, string password)
    {
        //Can be reused for any POST
        WebRequest request = WebRequest.Create(“http://jasperc:3000/api/session”);
        var user = new Dictionary<string, string>();
    }
``` 

Will produce:

        private string GetToken(string userName, string password)
        {
            //Can be reused for any POST
            WebRequest request = WebRequest.Create(“http://jasperc:3000/api/session”);
            var user = new Dictionary<string, string>();
        }

Ok I’ll take off my OCD :hammer_and_wrench: :tophat: off now :wink:

1 Like

I just copied and pasted from Visual Studio, then used the preformatted text option. I’ll have a play with the .cs stuff now.

edit: Now updated - very nice too - thanks

1 Like