1
votes

I have been trying to set up a function to call the Jira Rest API with parameters to then be able to create an issue in Jira. To call the Rest API Jira provided a documentation which describes how to call the Rest API here. On the website, the CURL and the JSON are given. Here is the REST API request I tried to set up in C#:

curl -D- -u peno.ch:yourpassword -H "Content-Type: application/json" --data @foo.json https://jira-test.ch.*******.net/rest/api/latest/issue/

This is the foo.json payload:

{
    "fields": {
   "project":
   {
      "key": "FOO"
   },
   "summary": "Test the REST API",
   "issuetype": {
      "name": "Task"
   }
  }
 }

I have tried to Implement a HttpWebRequest to call the Rest API and also I have tried with a WebClient. None of them worked. I kind of understand the API but I think I haven't got the parameters right, I think I am doing something wrong there. Also on Google, I didn't find any solution.

I am getting an Internal error from Jira when executing the function below. (no specific information on the error)

public static void CreateJiraRequest(JiraApiObject jiraApiObject)
{
    string url = "https://jira-test.ch.*******.net/rest/api/latest/issue/";
    string user = "peno.ch";
    string password = "****";

    var client = new WebClient();        
    string data = JsonConvert.SerializeObject(jiraApiObject);
    client.Credentials = new System.Net.NetworkCredential(user, password);
    client.UploadStringTaskAsync(url, data);
}

This is my JiraApiObject which exactly translates to the Json payload shown above.

public class JiraApiObject
{
    public class Project
    {
        public string key { get; set; }
    }

    public class Issuetype
    {
        public string name { get; set; }
    }

    public class Fields
    {
        public Project project { get; set; }
        public Issuetype issuetype { get; set; }
        public string summary { get; set; }
    }

    public class RootObject
    {
        public Fields fields { get; set; }
    }
}

When I execute the CURL command on the console everything works I just couldn't figure out how to structure the WebClient or HttpWebRequest.

I find that many Jira users face this problem and there is not a single good solution I could find on the internet. I hope to find a solution and help others who have the same problem by raising this question.

2
Have you checked that the JSON you're generating is correct? Try outputting it a text file or to Console and read it (possibly also post it/ state that it is correct) - MindSwipe
I converted it an reviewed it, it is identical to the JSON payload I have shown. - Mrs KOODA
There are a lot of questions asking how to translate a curl command to .NET code. This isn't about JIRA. What does doesn't work mean, what is the error? What does that command line do? Does it perform a POST? A PUT? --data suggests a POST. - Panagiotis Kanavos
It's also using basic authentication. This means the username/password are sent in cleartext as part of a header. Credentials doesn't know which authentication scheme to use so it starts with the most secure one - Windows Authentication. As this similar question shows, basic is used only if Windows auth isnt' available. You need to format the Authentication header in code - Panagiotis Kanavos

2 Answers

2
votes

In general, its best practice (many a times necessary) that you explicitly specify the content type, HTTP method, etc whenever you make a REST API call. Also, I prefer using HttpWebRequest object to make REST API calls. Here is the re-factored code:

public static void CreateJiraRequest(Chat jiraApiObject)
{
    string url = "https://jira-test.ch.*******.net/rest/api/latest/issue/";
    string user = "peno.ch";
    string password = "****";

    var request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "POST";
    request.ContentType = "application/json";
    request.Credentials = new System.Net.NetworkCredential(user, password);

    string data = JsonConvert.SerializeObject(jiraApiObject);

    using (var webStream = request.GetRequestStream())
    using (var requestWriter = new StreamWriter(webStream, System.Text.Encoding.ASCII))
    {
        requestWriter.Write(data);
    }

    try
    {
        var webResponse = request.GetResponse();
        using (var responseReader = new StreamReader(webResponse.GetResponseStream()))
        {
            string response = responseReader.ReadToEnd();
            // Do what you need to do with the response here.
        }
    }
    catch (Exception ex)
    {
        // Handle your exception here
        throw ex;
    }
}

Also, ensure that the JSON structure after serialising JiraApiObject matches the required JSON structure of the API in question. For your convenience, you may want to consider using JsonObject and JsonProperty attributes on the classes and properties so that you name them the way the API expects.

0
votes

Following is your backend RESTapi code in C#

    public class JiraController : ApiController
    {
        public IJiraInterface repository = new JiraRepository();

        [Route("api/Jira/getTickets")]
        [HttpGet]
        [EnableCors(origins: "http://localhost:8080", headers: "*", methods: "*")]
        public Object getTickets(string startAt,string maxResults)
        {
            return repository.getTickets(startAt,maxResults);
        }

        [Route("api/Jira/createTicket")]
        [HttpPost]
        [EnableCors(origins: "http://localhost:8080", headers: "*", methods: "*")]
        public Object createTicket(IssueModel issueModelObject)
        {
            return repository.createTicket(issueModelObject);
        }
    }

This is how your interface class should look

public interface IJiraInterface
{
    Object getTickets(string startAt,string maxResults);
    Object createTicket(IssueModel issueObj);
}

This is how entity looks like

    public class IssueModel
    {
      #region Properties
      public string RequesterType { get; set; }
      public string Summary { get; set; }
      public string Description { get; set; }
      public string Email { get; set; }
      #endregion
    }

This is your repository class

public class JiraRepository : IJiraInterface
{
      public JiraRepository()
      {
      }
      public Object getTickets(string startAt, string maxResults)
      {
        string URL = "https://YOUR_SUB_DOMAIN.atlassian.net/rest/api/3/search?jql=project=PROJECT_NAME"+ 
            "&startAt="+ startAt + 
            "&maxResults=" + maxResults;
        
        HttpWebRequest httpWReq = (HttpWebRequest)WebRequest.Create(URL);
        httpWReq.PreAuthenticate = true;
        httpWReq.Headers.Add("Authorization", "Basic " + getAuthorization());
        httpWReq.Headers.Add("Access-Control-Allow-Origin", "*");
        

        HttpWebResponse response = (HttpWebResponse)httpWReq.GetResponse();
        StreamReader reader = new StreamReader(response.GetResponseStream());
        string responseString = reader.ReadToEnd();
        return JObject.Parse(responseString);
      }
      public Object createTicket(IssueModel issueObj)
      {
        string URL = "https://YOUR_SUB_DOMAIN.atlassian.net/rest/api/3/issue";

        HttpWebRequest httpWReq = (HttpWebRequest)WebRequest.Create(URL);
        httpWReq.ContentType = "application/json";
        httpWReq.PreAuthenticate = true;
        httpWReq.Method = "POST";
        using (var streamWriter = new StreamWriter(httpWReq.GetRequestStream()))
        {
            string json =
            "{\n  \"update\": {},\n  \"properties\" : [\n      {\n          \"key\":\"requestType\",\n          \"value\":\""+ issueObj.RequesterType + "\"\n      }\n  ],\n\n  \"fields\": {\n    \"summary\": \"" + issueObj.Summary + "\",\n    \"issuetype\": {\n      \"id\": \"10203\"\n    },\n    \"project\": {\n      \"id\": \"10512\"\n    },\n  \"description\": {\n      \"type\": \"doc\",\n      \"version\": 1,\n      \"content\": [\n        {\n          \"type\": \"paragraph\",\n          \"content\": [\n            {\n              \"text\": \"" + issueObj.Description + "\",\n              \"type\": \"text\"\n            }\n          ]\n        }\n      ]\n    },\n    \"priority\": {\n      \"id\": \"10000\"\n    }\n  }\n}";
            streamWriter.Write(json);
        }
        httpWReq.Headers.Add("Authorization", "Basic " + getAuthorization());
        httpWReq.Headers.Add("Access-Control-Allow-Origin", "*");

        try
        {
            HttpWebResponse response = (HttpWebResponse)httpWReq.GetResponse();
            StreamReader reader = new StreamReader(response.GetResponseStream());
            string responseString = reader.ReadToEnd();
            return JObject.Parse(responseString);
        }
        catch(Exception e)
        {
            return JObject.Parse(e.Message);
        }

      }
    
      public string getAuthorization()
      {
        var username = "YOUR_JIRA_USERNAME_KEY";
        var password = "YOUR_JIRA_PASSWORD_KEY";
        return Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));

      } 
}

For frontend gothrough the following link https://stackoverflow.com/a/70280761/4921412