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.
333 lines
8.0 KiB
333 lines
8.0 KiB
![]()
2 years ago
|
---
|
||
|
sidebar_position: 2
|
||
|
title: Graphql
|
||
|
---
|
||
|
|
||
|
For our examples we will use a small example project based on an SQLite database.
|
||
|
|
||
|
This example is available [here](/DemoGraphQL.zip).
|
||
|
|
||
|
## 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:
|
||
|
|
||
|
```csharp title="wwwroot/appsettings.json"
|
||
|
{
|
||
|
"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.
|
||
|
|
||
|

|
||
|
|
||
|
Or using the Package Manager console: `PM> Install-Package GraphQL.Client`
|
||
|
|
||
|
Install the GraphQL serialization nuget `GraphQL.Client.Serializer.Newtonsoft`:
|
||
|
|
||
|

|
||
|
|
||
|
`PM> Install-Package GraphQL.Client.Serializer.Newtonsoft`
|
||
|
|
||
|
After installation, we will save it in the `Program` class:
|
||
|
|
||
|
```csharp {8} title="Program.cs"
|
||
|
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:
|
||
|
|
||
|
```csharp title="OwnerConsumer.cs"
|
||
|
public class OwnerConsumer
|
||
|
{
|
||
|
private readonly IGraphQLClient _client;
|
||
|
|
||
|
public OwnerConsumer(IGraphQLClient client)
|
||
|
{
|
||
|
_client = client;
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Now let's register this class:
|
||
|
|
||
|
```csharp {9} title="Program.cs"
|
||
|
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:
|
||
|
|
||
|
```csharp title="Models/TypeOfAccount.cs"
|
||
|
public enum TypeOfAccount
|
||
|
{
|
||
|
Cash,
|
||
|
Savings,
|
||
|
Expense,
|
||
|
Income
|
||
|
}
|
||
|
```
|
||
|
|
||
|
```csharp title="Models/Account.cs"
|
||
|
public class Account
|
||
|
{
|
||
|
public Guid Id { get; set; }
|
||
|
public TypeOfAccount Type { get; set; }
|
||
|
public string Description { get; set; }
|
||
|
}
|
||
|
```
|
||
|
|
||
|
```csharp title="Models/Owner.cs"
|
||
|
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.
|
||
|
|
||
|
```csharp title="Models/OwnerInput.cs"
|
||
|
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:
|
||
|
|
||
|
```csharp title="OwnerConsumer.cs"
|
||
|
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:
|
||
|
|
||
|
```csharp title="ResponseTypes/ResponseOwnerCollectionType.cs"
|
||
|
public class ResponseOwnerCollectionType
|
||
|
{
|
||
|
public List<Owner> Owners { get; set; }
|
||
|
}
|
||
|
```
|
||
|
|
||
|
```csharp title="ResponseTypes/ResponseOwnerType.cs"
|
||
|
public class ResponseOwnerType
|
||
|
{
|
||
|
public Owner Owner { get; set; }
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### Get Query
|
||
|
|
||
|
```csharp title="OwnerConsumer.cs"
|
||
|
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
|
||
|
|
||
|
```csharp title="OwnerConsumer.cs"
|
||
|
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
|
||
|
|
||
|
```csharp title="OwnerConsumer.cs"
|
||
|
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
|
||
|
|
||
|
```csharp title="OwnerConsumer.cs"
|
||
|
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:
|
||
|
|
||
|
```html title="Pages/Consume.razor"
|
||
|
@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:
|
||
|
|
||
|
```csharp title="Pages/Consume.razor.cs"
|
||
|
public partial class Consume
|
||
|
{
|
||
|
private List<Owner> Owner;
|
||
|
|
||
|
[Inject]
|
||
|
public OwnerConsumer Consumer { get; set; }
|
||
|
|
||
|
protected override async Task OnInitializedAsync()
|
||
|
{
|
||
|
this.Owner = await Consumer.GetAllOwners();
|
||
|
}
|
||
|
}
|
||
|
```
|