-
Notifications
You must be signed in to change notification settings - Fork 14
Queries and mutations
Let's suppose that schema.graphql file contains the following:
schema {
query: Queries
mutation: Mutation
}
type Queries {
me: User!
user(id: Int!): User
}
type Mutation {
addUser(firstName: String!, lastName: String!): User!
addUserProfileImage(userId: Int! file: Upload!): Int!
}
type User {
id: Int!
firstName: String!
lastName: String!
role: Role!
}
type Role {
id: Int!
name: String!
}
and we want to execute the query like that:
query { me { id firstName lastName } }
Here how we can achieve it with ZeroQL "lambda" syntax:
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://localhost:10000/graphql");
var client = new TestServerGraphQLClient(httpClient);
var response = await client.Query(o => o.Me(o => new { o.Id, o.FirstName, o.LastName }));
Console.WriteLine($"GraphQL: {response.Query}"); // GraphQL: query { me { id firstName lastName } }
Console.WriteLine($"{response.Data.Id}: {response.Data.FirstName} {response.Data.LastName}"); // 1: Jon Smith
You can pass arguments inside lambda if needed:
var userId = 1;
var response = await client.Query(o => o.User(userId, o => new User(o.Id, o.FirstName, o.LastName)));
Console.WriteLine($"GraphQL: {response.Query}"); // GraphQL: query ($id: Int!) { user(id: $id) { id firstName lastName } }
Console.WriteLine($"{response.Data.Id}: {response.Data.FirstName} {response.Data.LastName}"); // 1: Jon Smith
There is a limitation for lambda syntax. The variable should be a local variable or a parameter of the function. Otherwise, it will not be included in the lambda closure. As a result, ZeroQL would not be able to get a value.
Here is an example of the function parameter:
public Task<User> GetUser(int userId)
{
var response = await client.Query(o => o.User(userId, o => new User(o.Id, o.FirstName, o.LastName)));
return response.Data;
}
To be clear, you don't need actively account for it. ZeroQL will analyze and report errors if something is wrong.
For example the next sample will not work:
public int UserId { get; set; }
public Task<User> GetUser()
{
var response = await client.Query(o => o.User(UserId, o => new User(o.Id, o.FirstName, o.LastName))); // ZeroQL will report a compilation error here
return response.Data;
}
Also, there is a way to avoid lambda closure:
var variables = new { Id = 1 };
var response = await client.Query(variables, static (i, o) => o.User(i.Id, o => new User(o.Id, o.FirstName, o.LastName)));
You can fetch attached fields:
var variables = new { Id = 1 };
var response = await client.Query(
variables,
static (i, o) => o
.User(i.Id,
o => new
{
o.Id,
o.FirstName,
o.LastName,
Role = o.Role(role => role.Name)
}));
Console.WriteLine($"GraphQL: {response.Query}"); // GraphQL: query GetUserWithRole($id: Int!) { user(id: $id) { id firstName lastName role { name } } }
Console.WriteLine($"{response.Data.Id}: {response.Data.FirstName} {response.Data.LastName}, Role: {response.Data.Role}"); // 1: Jon Smith, Role: Admin
In more complex queries, the "lambda" syntax may look verbose, and extracting requests into a separate entity would be nice. Now it is possible to do it via the "request" syntax. Here is an example:
// define a request
public record GetUserQuery(int Id) : GraphQL<Queries, UserModel?>
{
public override UserModel? Execute(Queries query)
=> query.User(Id, o => new UserModel(o.Id, o.FirstName, o.LastName));
}
// execute a request
var response = await client.Execute(new GetUserQuery(variables.FriendId));
Console.WriteLine(response.Query); // query GetUserQuery($id: Int!) { user(id: $id) { id firstName lastName } }
Console.WriteLine(response.Data); // UserModel { Id = 2, FirstName = Ben, LastName = Smith }
You need to create a record from the base record GraphQL<TOperationType, TResult>
. Where the TOperationType
is a root query type(Query
, Mutation
) that associated with the GraphQLClient<TQuery, TMutataion>
instance.