Search code examples
c#apiharvest

Harvest (timecard app) API


Harvest is the time tracking application that I use at my job. While the web UI is quite simple, there are a few custom features I would like to add. I noticed they have an API... So I want to make a custom desktop client in C# for it.

Just looking at the page, its not very informative. The C# sample that you can find (after doing some digging) doesn't help much either. So... How in the world do I use the API with C#?

Link to API page

Any help would be greatly appreciated :)


Solution

  • Harvest is using a REST API, so what is does is you do a get/put/post request to a web address on the server and it will return a result (usually formatted in XML or JSON (appears to be XML in this case)). A quick Google search returned this tutorial on how to use a REST API, hopefully that will be enough for what you need. If not, feel free to ask us about specific problems you are having using REST and C#

    Here I will try to add some more comments to their sample:

    using System;
    using System.Net;
    using System.IO;
    using System.Text;
    using System.Security.Cryptography.X509Certificates;
    using System.Net.Security;
    
    class HarvestSample
    {
        //This is used to validate the certificate the server gives you,
        //it allays assumes the cert is valid.
        public static bool Validator (object sender, X509Certificate certificate,
            X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }
    
        static void Main(string[] args)
        {
            //setting up the initial request.
            HttpWebRequest request;
            HttpWebResponse response = null;
            StreamReader reader;
            StringBuilder sbSource;
            //1. Set some variables specific to your account.
            //This is the URL that you will be doing your REST call against.
            //Think of it as a function in normal library.
            string uri = "https://yoursubdomain.harvestapp.com/projects";
            string username="[email protected]";
            string password="yourharvestpassword";
            string usernamePassword = username + ":" + password;
    
            //This checks the SSL cert that the server will give us,
            //the function is above this one.
            ServicePointManager.ServerCertificateValidationCallback = Validator;
    
            try
            {
                //more setup of the connection
                request = WebRequest.Create(uri) as HttpWebRequest;
                request.MaximumAutomaticRedirections = 1;
                request.AllowAutoRedirect = true;
    
                //2. It's important that both the Accept and ContentType headers
                //are set in order for this to be interpreted as an API request.
                request.Accept = "application/xml";
                request.ContentType = "application/xml";
                request.UserAgent = "harvest_api_sample.cs";
                //3. Add the Basic Authentication header with username/password string.
                request.Headers.Add("Authorization", "Basic " + Convert.
                    ToBase64String(new ASCIIEncoding().GetBytes(usernamePassword)));
                //actually perform the GET request
                using (response = request.GetResponse() as HttpWebResponse)
                {
                    //Parse out the XML it returned.
                    if (request.HaveResponse == true && response != null)
                    {
                        reader = new StreamReader(response.GetResponseStream(),
                            Encoding.UTF8);
                        sbSource = new StringBuilder(reader.ReadToEnd());
                        //4. Print out the XML of all projects for this account.
                        Console.WriteLine(sbSource.ToString());
                    }
                }
            }
            catch (WebException wex)
            {
                if (wex.Response != null)
                {
                    using (HttpWebResponse errorResponse = (HttpWebResponse)wex.Response)
                    {
                        Console.WriteLine(
                        "The server returned '{0}' with the status code {1} ({2:d}).",
                        errorResponse.StatusDescription, errorResponse.StatusCode,
                        errorResponse.StatusCode);
                    }
                }
                else
                {
                    Console.WriteLine( wex);
                }
            }
            finally
            {
                if (response != null) { response.Close(); }
            }
        }
    }