I have been looking for a way to paginate on a standard relay graphql query, rather than creating a fragment and paginating on that. I havent really been able to find any documentation on how to achieve such a thing. I just want to run the query, come up with the first n records, and then run the query again (although i read thats not necessarily best practice, and then load the next 20 but increasing the count and running the query... has anyone done such a thing?
What I want in theory is...
const = useLazyLoadQuery{
data,
loadNext,
loadPrevious,
hasNext,
hasPrevious,
isLoadingNext,
isLoadingPrevious,
refetch, // For refetching connection
} = usePaginationFragment(
graphql`
fragment Table_user on User
#refetchable(queryName: "UserQuery")
#argumentDefinitions(
count: { type: "Int", defaultValue: 20 }
cursor: { type: "String" }
) {
query UserQuery(
$first: Int!,
$after: String
) {
users(search: $search) {
id
name
phone
email
postalCode
status
referralCode
products
updatedAt
nextAssignmentOn
}
}
}
I'm sure theres a way to do this, but many attempts have failed
usePaginationFragment does not do any fetch
you need to useLazyLoadQuery or usePreloadQuery to do the fetch
useFragment, usePaginationFragment only declares data requirements for fragments
check the new example here https://github.com/relayjs/relay-examples/pull/104
Related
I using https://hygraph.com/, and I want insert (create many products) in a single GraphQL request.
At the moment I know how to insert one product:
mutation {
createProduct(data: { title: "Face Mask", slug: "dfavce-mask", price: 1000 }) {
id
}
}
I read the documentation, but I didn't see information about bulk creation records.
Link for hygraph documentation:
https://hygraph.com/docs/api-reference/content-api/mutations#create-entries
The top-level query you show is just a query against the Mutation type (or another type specified in the schema). Like any other query, it can have multiple fields. At a technical level, the only special thing about GraphQL mutations is that, if you do have multiple fields, they execute sequentially.
Also like other queries, if you want to request the same field multiple times (run similarly-named mutations) you need to use an alias to disambiguate the results.
mutation {
createFaceMask: createProduct(data: { title: "Face Mask" }) { id }
createHandSanitizer: createProduct(data: { title: "Hand Sanitizer" }) { id }
}
I have a useQuery that returns data of the first item inserted. For context, I have an ecommerce website with grocery products, suppose I add an apple with quantiy of 4. Next, when I add another order with quantiy 10, it adds correctly in the database and I get correct results in the apollo playground. But when I am pulling data using the below code in Apollo client it has all the orders of that user with different order ids but has the quantiy of the first order made for apple.
const { loading, error, data } = useQuery(queries.GET_USER_ORDERS, {
fetchPolicy: "cache-and-network",
variables: {
userId: currentUser.uid,
},
});
Graphql query:
const GET_USER_ORDERS = gql`
query Query($userId: String) {
userOrders(userId: $userId) {
_id
userId
products {
_id
name
price
orderedQuantity
}
status
createdAt
flag
total
}
}
`;
So essentially I am seeing all products, but with quantity of 4 for each. How can I fix this?
Change fetch policy
fetchPolicy: "no-cache",
also check if you are updating this query result after new order placing mutation (if you are it may cause updating with wrong values )
if you set fetchPolicy: "no-cache" you don't have to update query result after mutation
I am fairly newbie when it comes down to graphql. I have the following schema
type query {
allJobs (
limit: Int
cursorId: String
): JobSearchResults!
type JobSearchResults {
jobs: [Job!]
hasMoreJobs: Boolean!
}
}
So there is the query allJobs and the result is an object with jobs array and a simply boolean hasMoreJobs to signal the end of the jobs.
On the client side I am able to query this and get results, but I am totally confused on how to cache these results. On ApolloClient I have the following:
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
// cache the previous results and concat the new results to original data
allJobs: concatPagination(),
},
},
},
}),
I know that this would work if I was just returning an array of jobs like that.
type query {
allJobs (
limit: Int
cursorId: String
): [Jobs]!
My question is if there is a way to use concatPagination to cache only the jobs: [Job!] from the original query.
Or if there is a better way to deal with this problem? Maybe I need to rethink and reconstruct the original schema?
I think you'll find the solution of your problem here:
https://www.apollographql.com/blog/pagination-and-infinite-scrolling-in-apollo-client-59ff064aac61/
For a mutation addVoucher there are a limited list of potential errors that can occur.
Voucher code invalid
Voucher has expired
Voucher has already been redeemed
At the moment I'm throwing a custom error when one of these occurs.
// On the server:
const addVoucherResolver = () => {
if(checkIfInvalid) {
throw new Error('Voucher code invalid')
}
return {
// data
}
}
Then on the client I search the message description so I can alert the user. However this feels brittle and also the GraphQL API doesn't automatically document the potential errors. Is there a way to define the potential errors in the GraphQL schema?
Currently my schema looks like this:
type Mutation {
addVoucherResolver(id: ID!): Order
}
type Order {
cost: Int!
}
It would be nice to be able to do something like this:
type Mutation {
addVoucherResolver(id: ID!): Order || VoucherError
}
type Order {
cost: Int!
}
enum ErrorType {
INVALID
EXPIRED
REDEEMED
}
type VoucherError {
status: ErrorType!
}
Then anyone consuming the API would know all the potential errors. This feels like a standard requirement to me but from reading up there doesn't seem to be a standardises GraphQL approach.
It's possible to use a Union or Interface to do what you're trying to accomplish:
type Mutation {
addVoucher(id: ID!): AddVoucherPayload
}
union AddVoucherPayload = Order | VoucherError
You're right that there isn't a standardized way to handle user-visible errors. With certain implementations, like apollo-server, it is possible to expose additional properties on the errors returned in the response, as described here. This does make parsing the errors easier, but is still not ideal.
A "Payload" pattern has emerged fairly recently for handling these errors as part of the schema. You see can see it in public API's like Shopify's. Instead of a Union like in the example above, we just utilize an Object Type:
type Mutation {
addVoucher(id: ID!): AddVoucherPayload
otherMutation: OtherMutationPayload
}
type AddVoucherPayload {
order: Order
errors: [Error!]!
}
type OtherMutationPayload {
something: Something
errors: [Error!]!
}
type Error {
message: String!
code: ErrorCode! # or a String if you like
}
enum ErrorCode {
INVALID_VOUCHER
EXPIRED_VOUCHER
REDEEMED_VOUCHER
# etc
}
Some implementations add a status or success field as well, although I find that making the actual data field (order is our example) nullable and then returning null when the mutation fails is also sufficient. We can even take this one step further and add an interface to help ensure consistency across our payload types:
interface Payload {
errors: [Error!]!
}
Of course, if you want to be more granular and distinguish between different types of errors to better document which mutation can return what set of errors, you won't be able to use an interface.
I've had success with this sort of approach, as it not only documents possible errors, but also makes it easier for clients to deal with them. It also means that any other errors that are returned with a response should serve as an immediately red flag that something has gone wrong with either the client or the server. YMMV.
You can use scalar type present in graphql
just write scalar JSON and return any JSON type where you want to return it.
`
scalar JSON
type Response {
status: Boolean
message: String
data: [JSON]
}
`
Here is Mutation which return Response
`
type Mutation {
addVoucherResolver(id: ID!): Response
}
`
You can return from resolver
return {
status: false,
message: 'Voucher code invalid(or any error based on condition)',
data: null
}
or
return {
status: true,
message: 'Order fetch successfully.',
data: [{
object of order
}]
}
on Front end you can use status key to identify response is fetch or error occurs.
I'm trying to have a representation of nodes on GraphQL more akin to what jsonapi would be like http://jsonapi.org/
What I mean is if we take one of the examples on GraphQL
{
hero {
name
# Queries can have comments!
friends {
name
}
}
}
Have a representation that would be more along these lines
{
hero {
name
# Queries can have comments!
friends {
id
}
},
friends {
id, name
}
}
Is that at all possible in GraphQL
Thanks
It is possible, and there's nothing wrong with having a friends field. In GraphQL terms you can have the following part of the schema:
type User {
id: ID
name: String
firends: [User]
}
type RootQuery {
hero: User
friends(forUserId: ID!): [User]
}
And then you can query this as you like – you can ask for friends separately:
{
friends(forUserId: "12") {
id, name
}
}
But the whole idea of GraphQL is that you don't have to do multiple queries to get the information you need. If you just need a list of users – that's a reasonable query, that most people have (with arguments for pagination and so on). With that said, there's no reason to fetch a list of IDs and to send another fetch query for the data right after that.