How can I provide input field arguments with apollo federation 2? - go

I am trying to federate two of my micro services with apollo gql federation 2.
I have successfully connected the two services through the federation with the following schemas:
Subgraph1 - Product
type Product #key(fields: "id") {
id: ID!
title: String!
description: String
price: Int!
category: [Category!]
}
type Category #key(fields: "id") {
id: ID!
}
type Query {
product(id: ID!): Product
}
Subgraph 2 - Category
type Category #key(fields: "id") {
id: ID!
title: String
}
and the following query
query Product($productId: ID!) {
product(id: $productId) {
id
title
category {
id
title
}
}
}
gives a desired result
However, what if I wanted to add some filter on the returned categories for a given product. Lets say I only wanted to have the ones with title "sport", so the query would look like this instead:
query Product($productId: ID!) {
product(id: $productId) {
id
title
category(searchTerm: "sport") {
id
title
}
}
}
A normal way of doing the input argument would be simply just
type Product #key(fields: "id") {
id: ID!
title: String!
description: String
price: Int!
category(searchTerm: String): [Category!]
}
Is this achievable when federating the services? I am not sure how the input field is provided to the second subgraph?
I tried to add the input as a part of the type in the first subgraph, however it does not seem to pass the search term to the next graph.

Related

Can entities in a federated Apollo GraphQL schema have fields that are resolved separately from __resolveReference?

With a federated GraphQL model using Apollo, the docs state that "A reference resolver is responsible for returning all of the entity fields that this subgraph defines". But is it possible to have fields in a subgraph not returned from the __resolveReference function, which have their own separate resolvers?
For example, let's say this is the schema (in two subgraphs):
// Products subgraph
type Product #key(fields: "id") {
id: ID!
name: String!
price: Int
}
// Inventory subgraph
type Product #key(fields: "id") {
id: ID!
inStock: Boolean!
otherField: String!
}
Can you then have this in your resolvers in the inventory subgraph?
// Inventory subgraph
const resolvers = {
Product: {
__resolveReference({ id }) {
return { id, inStock: false };
},
otherField: () => 'Hello World!',
},
}

GraphQL query with multiple nested resolvers and mapping fields to arguments

From GraphQL Client's perspective, how do I perform a query with multiple nested resolvers where the fields from the parent are passed as arguments to the child resolver?
Here is a minimal example:
GraphQL Schema:
type Author {
id: ID!
name: String!
}
type Book {
id: ID!
title: String!
releaseDate: String!
}
type Query {
// Returns a list of Authors ordered by name, 'first' indicates how many entries to return
getAllAuthors(first: Int!): [Author]!
// Returns a list of Books ordered by releaseDate, 'first' indicates how many entries to return
getBooksByAuthorId(first: Int! authorId: ID!): [Book]!
}
Is it possible to write a query to get all authors and their last released book? Something around the lines:
query GetAuthorsWithLastBook($first: Int!) {
getAllAuthors(first: $first) {
authorId: id
name
lastBook: getBooksByAuthor(1, authorId) {
title
}
}
}
In the example above, I attempted to alias getAllAuthors.id as authorId and pass the alias down as argument to getBooksByAuthor(...) but that didn't work.
The key aspect of the problem is that I don't know the authorIds beforehand. I could fetch the authors first and build a query to fetch their last book but that will result in multiple queries and that is something I would like to avoid.
Update
A Java Kickstarter example is available here: https://www.graphql-java-kickstart.com/tools/schema-definition/
yes, on the graphql definition, you need to add lastBook in the Author
type Author {
id: ID!
name: String!
lastBook: [Book]
}
Next up u need to write the resolver for the lastBook
const resolvers = {
Query: {
Author {
lastBook: (parent, args) {
const userId = parent.id;
return getBooksByAuthor(userId, 1);
},
}
}
};

Using Apollo Federated GraphQL, is there a way to sort/paginate on a value from an external entity?

Is it possible to mark a field in an input to a query as requiring a field extended by a different service?
Using the federation-demo to illustrate my question, but keeping a little bit more simple. Having just an Account service and a Reviews service, and adding a karma field to the User, is it possible to filter reviews based on User karma.
Account service, adding a karma int to a User:
extend type Query {
me: User
}
type User #key(fields: "id") {
id: ID!
name: String
username: String
karma: Int!
}
Reviews service, adding a reviews Query:
extend type Query {
reviews(minKarma: Int): [Review!]!
}
type Review #key(fields: "id") {
id: ID!
body: String
author: User #provides(fields: "username")
product: Product
}
extend type User #key(fields: "id") {
id: ID! #external
username: String #external
karma: Int! #external
reviews: [Review]
}
extend type Product #key(fields: "upc") {
upc: String! #external
reviews: [Review]
}
In my resolver for Query.reviews, I want to filter out any review where review.author.karma is less than the specified minKarma.
How do I tell the gateway that when minKarma is specified in the Query input, I want the Account service to be queried first and a representation of users to be passed into the Reviews service, with the karma of each user attached to the review as the author, so that I can do the filter?
Circling back to the question at the top of this post, can I mark the minKarma field as requiring User.karma?
This is the questions plaguing me as well.

How to resolve subselections / relations in prisma (nested lists)

Let's take an example from the github repo of prisma:
We have a user, the user could have multiple posts, and one post could have multiple links.
My goal is, to retrieve all posts and all links.
This means, my response is a list (links) in a list (posts).
I want to map the values I get back as two nested lists.
datamodel.prisma
type User {
id: ID! #id
email: String! #unique
name: String
posts: [Post]!
}
type Post {
id: ID! #id
createdAt: DateTime! #createdAt
updatedAt: DateTime! #updatedAt
published: Boolean! #default(value: false)
title: String!
content: String
author: User!
links: [Link]!
}
type Link {
id: ID! #id
url: String
title: String
post: Post!
}
schema.graphql
type Query {
...
}
type Mutation {
...
}
type Link {
id: ID!
url: String
title: String
post: Post!
}
type Post {
id: ID!
createdAt: DateTime!
updatedAt: DateTime!
published: Boolean!
title: String!
content: String
author: User!
}
type User {
id: ID!
email: String!
name: String
posts: [Post]!
}
I want to query all posts of a user, and all of the links for every post in the response.
How would I query this request?
user {
id
posts {
id
links {
id
}
}
}
The above code snipper would not work.
EDIT
I want to use the following:
User: {
listPosts: (parent, args, context, info) {
return context.prisma.posts().links()
}
}
So in my response (data in front-end via react-apollo Query Component), I want to map over posts AND the links in each post.
BUT the links attribute in posts is null.
Is there another way to achieve this?!
According to the docs:
Prisma client has a fluent API to query relations in your database. Meaning you can simply chain your method calls to navigate the relation properties of the returned records. This is only possible when retrieving single records, not for lists. Meaning you can not query relation fields of records that are returned in a list.
In order to get around that limitation, you can use the $fragment method:
const fragment = `
fragment UserWithPostsAndLinks on User {
id
email
name
posts {
id
title
content
links {
id
url
title
}
}
}
`
const userWithPostsAndLinks = await prisma.user({ id: args.id }).$fragment(fragment)

Indexing List Type field in a GraphQL type from within a Query

Say I have the following GraphQL Schema
query {
allAuthors: [Author]
}
type Author {
id: ID!
name: String!
books: [Book]
}
type Book {
id: ID!
name: String!
author: Author!
}
Now I can successfully run the following query to get all the authors and their associated books
query {
allAuthors {
name,
books {
name
}
}
}
However, if I only want to get the first three books for all authors, how would I go about doing something like that? Can we index the books field in the Author type from within a query? If so, how?
I tried something like this and it doesn't work
query {
allAuthors {
name,
books[3] {
name
}
}
}
GraphQL doesn't have syntax for this.
You can add a "limit" parameter to a field, and this is common enough:
type Query {
allAuthors(limit: Int, offset: Int): [Author!]!
}
type Author {
id: ID!
name: String!
books(limit: Int, offset: Int): [Book!]!
}
If you add parameters like this to the schema, then the query you want (for all authors, get the first three books) could look like
{
allAuthors {
name
books(limit: 3) {
name
}
}
}

Resources