You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

8.0 KiB

sidebar_position title
2 Graphql

For our examples we will use a small example project based on an SQLite database.

This example is available here.

Creating a client application

We will create a client application to consume GraphQL.

Create a new Blazor WASM app.

Edit the appsettings.json file, adding an address to the GraphQL app:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "GraphQLURI": "https://localhost:44371/graphql",
  "AllowedHosts": "*"
}

Install the GraphQL.Client package in its latest version.

required library

Or using the Package Manager console: PM> Install-Package GraphQL.Client

Install the GraphQL serialization nuget GraphQL.Client.Serializer.Newtonsoft:

required library

PM> Install-Package GraphQL.Client.Serializer.Newtonsoft

After installation, we will save it in the Program class:

public static async Task Main(string[] args)
{
	var builder = WebAssemblyHostBuilder.CreateDefault(args);
	builder.RootComponents.Add<App>("#app");

	builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
	
	builder.Services.AddScoped<IGraphQLClient>(s => new GraphQLHttpClient(builder.Configuration["GraphQLURI"], new NewtonsoftJsonSerializer()));

	await builder.Build().RunAsync();
}

The next step is to create the OwnerConsumer class, which will store all requests and mutations:

public class OwnerConsumer
{
    private readonly IGraphQLClient _client;

    public OwnerConsumer(IGraphQLClient client)
    {
        _client = client;
    }
}

Now let's register this class:

public static async Task Main(string[] args)
{
	var builder = WebAssemblyHostBuilder.CreateDefault(args);
	builder.RootComponents.Add<App>("#app");

	builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
	
	builder.Services.AddScoped<IGraphQLClient>(s => new GraphQLHttpClient(builder.Configuration["GraphQLURI"], new NewtonsoftJsonSerializer()));
	builder.Services.AddScoped<OwnerConsumer>();

	await builder.Build().RunAsync();
}

We have finished everything regarding the configuration.

Creating model classes

We will create the model classes so that we can use the data from our queries:

public enum TypeOfAccount
{
    Cash,
    Savings,
    Expense,
    Income
}
public class Account
{
    public Guid Id { get; set; }
    public TypeOfAccount Type { get; set; }
    public string Description { get; set; }
}
public class Owner
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }

    public ICollection<Account> Accounts { get; set; }
}

Now we are going to create the Input class for the mutation actions.

public class OwnerInput
{
    public string Name { get; set; }
    public string Address { get; set; }
}

We have now prepared everything and are ready to start creating queries and mutations.

Creating queries and mutations to consume the GraphQL API

Open the OwnerConsumer class and add the GetAllOwners method:

public async Task<List<Owner>> GetAllOwners()
{
    var query = new GraphQLRequest
    {
        Query = @"
                query ownersQuery{
                  owners {
                    id
                    name
                    address
                    accounts {
                      id
                      type
                      description
                    }
                  }
                }"
    };

    var response = await _client.SendQueryAsync<ResponseOwnerCollectionType>(query);
    return response.Data.Owners;
}

As you can see, we are creating a new GraphQLRequest object which contains a Query property for the query we want to send to the GraphQL API. This query is the same one you can use with the UI.Playground tool.

To execute the query, call the SenQueryAsync method which accepts a response type (as a generic parameter) and the query. Finally, the code returns the list of owners from this response.

We don't have the ResponseOwnerCollectionType class, so let's create a new ResponseTypes folder and inside it create the two new classes:

public class ResponseOwnerCollectionType
{
    public List<Owner> Owners { get; set; }
}
public class ResponseOwnerType
{
    public Owner Owner { get; set; }
}

Get Query

public async Task<Owner> GetOwner(Guid id)
{
    var query = new GraphQLRequest
    {
        Query = @"
                query ownerQuery($ownerID: ID!) {
                  owner(ownerId: $ownerID) {
                    id
                    name
                    address
                    accounts {
                      id
                      type
                      description
                    }
                  }
                }",
        Variables = new { ownerID = id }
    };

    var response = await _client.SendQueryAsync<ResponseOwnerType>(query);
    return response.Data.Owner;
}

Create Mutation

public async Task<Owner> CreateOwner(OwnerInput ownerToCreate)
{
    var query = new GraphQLRequest
    {
        Query = @"
                mutation($owner: ownerInput!){
                  createOwner(owner: $owner){
                    id,
                    name,
                    address
                  }
                }",
        Variables = new {owner = ownerToCreate}
    };

   var response = await _client.SendMutationAsync<ResponseOwnerType>(query);
   return response.Data.Owner;
}

Update Mutation

public async Task<Owner> UpdateOwner(Guid id, OwnerInput ownerToUpdate)
{
    var query = new GraphQLRequest
    {
        Query = @"
                mutation($owner: ownerInput!, $ownerId: ID!){
                  updateOwner(owner: $owner, ownerId: $ownerId){
                    id,
                    name,
                    address
                  }
               }",
        Variables = new { owner = ownerToUpdate, ownerId = id }
    };

	var response = await _client.SendMutationAsync<ResponseOwnerType>(query);
	return response.Data.Owner;
}

Delete Mutation

public async Task<Owner> DeleteOwner(Guid id)
{
    var query = new GraphQLRequest
    {
        Query = @"
               mutation($ownerId: ID!){
                  deleteOwner(ownerId: $ownerId)
                }",
        Variables = new { ownerId = id }
    };

    var response = await _client.SendMutationAsync<ResponseOwnerType>(query);
    return response.Data.Owner;
}

Use in a Blazor page

Create a new Consume.razor page to test our code:

@page "/consume"

<h3>Consume</h3>

@if (Owner != null)
{
    <table class="table">
        <thead>
        <tr>
            <th>Id</th>
            <th>Name</th>
            <th>Address</th>
        </tr>
        </thead>
        <tbody>
        @foreach (var item in Owner)
        {
            <tr>
                <td>@item.Id</td>
                <td>@item.Name</td>
                <td>@item.Address</td>
            </tr>
        }
        </tbody>
    </table>
}

Create the page code:

public partial class Consume
{
	private List<Owner> Owner;

	[Inject]
	public OwnerConsumer Consumer { get; set; }

	protected override async Task OnInitializedAsync()
	{
		this.Owner = await Consumer.GetAllOwners();
	}
}