Making requests from code

Learn how to make programmatic requests in C#/.NET 5 to execute GraphQL queries and deserialize JSON responses.

In this section, we will consider making requests programatically to execute the following query:

Query

query read_glas($cid : Int, $pagesize : Int){
    useCompany(no: $cid) {
        generalLedgerAccount(first: $pagesize) {
            totalCount
            pageInfo {
                hasNextPage
                hasPreviousPage
                startCursor
                endCursor
            }
            items {
                accountNo
                name
            }
        }
    }
}
Result

{
  "data": {
    "useCompany": {
      "generalLedgerAccount": {
        "totalCount": 344,
        "pageInfo": {
          "hasNextPage": true,
          "hasPreviousPage": false,
          "startCursor": "MA==",
          "endCursor": "MjAw"
        },
        "items": [
          {
            "accountNo": 1000,
            "name": "Forskning og utvikling"
          },
          {
            "accountNo": 1020,
            "name": "Konsesjoner"
          },
          {
            "accountNo": 1030,
            "name": "Patenter"
          }
        ]
      }
    }
  }
}

Important

The code for the example described here is available on GitHub at GraphQLSamples/SimpleQuery.

C# / .NET 5 Example

If you need to make requests programatically and are using C# and .NET 5, you can do the following:

  1. Create a class to contain the actual query and potential variables.

    class QueryRequest
    {
       [JsonPropertyName("query")]
       public string query { get; set; }
    
       [JsonPropertyName("variables")]
       public Dictionary<string, object> variables { get; set; }
    }
    

    Note: The name of the C# class and its properties are not that important. However, the JSON text that is being sent in the body of the POST request must have the form shown in the following snippet (that contains a query for reading a first page of 100 records from the general ledger account table). Notice that query and variable must be in lower-case.

    {
       "query": "query read_glas($cid : Int, $pagesize : Int){\r\n useCompany(no: $cid) {\r\n generalLedgerAccount(first: $pagesize) {\r\n totalCount\r\n pageInfo {\r\n hasNextPage\r\n hasPreviousPage\r\n startCursor\r\n endCursor\r\n }\r\n items {\r\n accountNo\r\n name\r\n }\r\n }\r\n }\r\n}",
       "variables": {
          "cid" : 9112233,
          "pagesize" : 100
       }
    }
    

    You can use JSON attributes (they are similar whether you use Json.NET or System.Text.Json) to ensure the serialized JSON document has the correct shape regarless of the names of the C# classes, properties, or fields.

  2. Create classes to model the expected response, so that you can deserialize the JSON object returned by the server.

    public class GeneralLedgerAccountResponse
    {
       public Data data { get; set; }
    }
    
    public class Data
    {
       public Usecompany useCompany { get; set; }
    }
    
    public class Usecompany
    {
       public GeneralLedgerAccountConnection generalLedgerAccount { get; set; }
    }
    
    public class GeneralLedgerAccountConnection
    {
       public int totalCount { get; set; }
       public PageInfo pageInfo { get; set; }
       public GeneralLedgerAccount[] items { get; set; }
    }
    
    public class PageInfo
    {
       public bool hasNextPage { get; set; }
       public bool hasPreviousPage { get; set; }
       public string startCursor { get; set; }
       public string endCursor { get; set; }
    }
    
    public class GeneralLedgerAccount
    {
       public int accountNo { get; set; }
       public string name { get; set; }
    }
    
  3. Create a generic method that can execute a request and return the deserialized result.

    class Program
    {
       private static readonly HttpClient _client = new();
    
       private static async Task<TResponse> ExecuteQuery<TResponse>(QueryRequest request, 
                                                                   string url, 
                                                                   string accessToken)
       {
          try
          {
             _client.DefaultRequestHeaders.Authorization =
                new AuthenticationHeaderValue("Bearer", accessToken);
    
             using var response = await _client.PostAsJsonAsync(url, request);
             response.EnsureSuccessStatusCode();
    
             var body = await response.Content.ReadAsStringAsync();
             var content = await response.Content.ReadFromJsonAsync<TResponse>();
             return content;
          }
          catch (HttpRequestException ex)
          {
             Console.Error.WriteLine($"{ex.Message} (code: {ex.StatusCode.Value})");
          }
          catch (Exception ex)
          {
             Console.Error.WriteLine(ex.Message);
          }
    
          return default;
       }
    }
    
  4. Obtain an access token programatically. This is covered in Examples for setting up authorization: .NET Code Sample.

  5. Create a request string, execute it, and process the result.

    class Program
    {
       static async Task Main(string[] args)
       {
          var url = "https://business.visma.net/api/graphql";
          var accessToken = "...";
          var companyId = ...;
          var pageSize = 100;
    
          var request = new QueryRequest()
          {
             query = 
    @"query read_glas($cid : Int, $pagesize : Int){
    useCompany(no: $cid) {
       generalLedgerAccount(first: $pagesize) {
             totalCount
             pageInfo {
                hasNextPage
                hasPreviousPage
                startCursor
                endCursor
             }
             items {
                accountNo
                name
             }
       }
    }
    }",
             variables = new Dictionary<string, object>
             {
                {"cid", companyId},
                {"$pagesize", pageSize}
             }
          };
    
          var result = await ExecuteQuery<GeneralLedgerAccountResponse>(request, url, accessToken);
          if (result?.data?.useCompany?.generalLedgerAccount?.items is object)
          {
             foreach (var gla in result.data.useCompany.generalLedgerAccount.items)
             {
                Console.WriteLine($"{gla.accountNo} - {gla.name}");
             }
          }
       }
    }
    
Last modified September 24, 2024