How do I retrieve all users from a GitLab deployment using the GraphQL interface? - graphql

I am trying to load user information from GitLab so that I can associate usernames with issues. When querying for issues, the assignee username is not directly available. Instead, a user ID is available.
If I execute this GraphQL query using the /-/graphql-explorer endpoint on my GitLab deployment:
query {
users {
nodes {
id
name
username
}
}
}
then 91 users are returned. This is clearly not all users on the deployment, though. There are users I know exist but which are not included in the result. I can query for them individually using this GraphQL query:
query {
user(username: "someusername") {
id
}
}
and receive a result which seems to correctly describe the user.
Why are some users omitted from the results for this query? I know that large result sets require dealing with pagination but the default page size is supposed to be 100 and I am receiving fewer results than this. Additionally, if I request pageinfo and ask for the users after the resulting endCursor I receive no items.
How do I submit a query that gets me all users? Failing that, how do I submit a query that will get me all users which could be assignees for a a group (or, failing that, for a list of projects)?

From the documentation :
By default, GitLab’s GraphQL API will return only the first 100 records of any collection. This can be changed by using first or last arguments. Both arguments take a value, so first: 10 will return the first 10 records, and last: 10 the last 10 records.
So you have to do the pagination yourself, your first query would be for example :
query {
users(first: 10) {
edges {
node {
id
name
username
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
Then use the PageInfo result values to know if you have more pages to fetch and the cursor ID to fetch the next page, for example you could get the following result :
...
"pageInfo": {
"endCursor": "eyJpZCI6Ijc****************zNjk0MDUwMDAgOVRDIn0",
"hasNextPage": true
}
So for the next page, you have to query :
query {
users(first: 10, after: "eyJpZCI6IjcxMj**********************Ni4zNjk0MDUwMDAgOVRDIn0") {
edges {
node {
id
name
username
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
And so on until hasNextPage returns false.
For more info about pagination and cursors, see GraphQL documentation : https://graphql.org/learn/pagination/

Related

Why I am I getting the same value for a field in all of my array objects for useQuery?

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

Contentful GraphQL endpoint: how to retrieve all entries of a content type

{
Post {
name
}
}
While trying to retrieve all the entries on a content type, it only gives error of:
"Argument \"id\" of required type \"String!\" was not provided."
Since id field is required. How do I get all entries of a content type then?
Ref: https://www.contentful.com/developers/docs/references/graphql/
From docs here:
The produced Query object exposes two fields that you can use to query content of that type: one to fetch individual content documents (friendlyUser in the example) and another to do queries over all the content of the type (friendlyUserCollection).
So for any resource that you want to retrieve all entries of, you need to append Collection at the end of its id, then use items field to retrieve all entries. As in:
{
PostCollection {
items {
name
}
}
}
Apart from docs, you can also view all available resources at corresponding GraphiQL instance here, which could be pretty useful:
https://graphql.contentful.com/content/v1/spaces/{SPACE_ID}/explore?access_token={ACCESS_TOKEN}
Search or select Query to see all schemas:
Query a single id
I think you can try this in the GraphQL playgound
http://localhost:8000/___graphql
query PostById($id: String!) {
contentfulPost(id: { eq: $id }) {
name
}
}
and add a QUERY VARIABLE
{
"id": "my-awesome-id"
}
Query all the Posts
How do I get all entries of a content type then?
On the GraphQL playground, you should be able to do something like this
{
allContentfulPost {
nodes {
name
}
}
}

Is it possible for vue-apollo to return different results from the Playground?

I have a GraphQL query called myAccounts which returns an array of accounts. When I go to the Playground and call the query:
{
accounts {
email
}
}
I get this result:
"data": {
"accounts": [
{
"email": "zach#email-one.com",
},
{
"email": "zach#email-two.com",
}
]
}
However, when I am in my Component, vue-apollo returns two items in the array, but seems to overwrite the second item with the first. Here is the query (in MyAccounts.gql):
query myAccounts {
accounts: myAccounts {
email
}
}
and here is the Apollo query in the component:
import MY_ACCOUNTS_QUERY from '~/apollo/queries/MyAccounts'
...
apollo: {
accounts: {
query: MY_ACCOUNTS_QUERY,
result(data) {
console.log(JSON.stringify(data))
}
}
}
and here is what vue-apollo logs out through the result:
{
"data":{
"accounts":[
{
"email":"zach#email-one.com",
"__typename":"Account"
},
{
"email":"zach#email-one.com",
"__typename":"Account"
}
]
},
"loading":false,
"networkStatus":7,
"stale":false
}
Expected behavior
I would expect the data returned in the Playground to be identical to what vue-apollo is fetching.
Versions
vue: 2.6.10
vue-apollo: #nuxtjs/apollo: 4.0.0-rc18
Additional context
I thought the result hook would be the best way to debug, but any other suggestions gladly welcomed. I assumed that this was a bug in our code, but I cannot figure out what could be causing the repetition (and mismatch).
Apollo normalizes its cache based on the __typename and the id (or _id) field. You need to include an id or _id field in your selection set alongside email. Failing to do so results in both objects being assigned the same key. If you don't have an id field to request, you'll need to provide a custom dataIdFromObject function as shown here.
From Guillaume Chau (https://github.com/Akryum):
This is because the Apollo Client cache can't compute a different ID
for the two items, so you endup with Account:undefined (or similar)
for both. Open the Apollo devtools and look at the myAccounts key in
the cache.
Learn more:
https://www.apollographql.com/docs/react/caching/cache-configuration/

Display more than 100 entries through GraphQL API

I have tired pagination using endCursor and hasNextPage in github grpahQL API to get more than 100 data. Query I used is:
query {
organization(login:"XXX") {
repository(name:"XX") {
pullRequests(first:100, states:[OPEN], after: "XXX" ) {
pageInfo{
hasNextPage
endCursor
}
}
}
It is working. But in order to access further details,iterative pagination needs to be done. Can anyone provides an efficient alternative to traverse all pages programatically in GraphQL API?
Taking inspiration from Simon Willison's 'Paginating through the GitHub GraphQL API with Python' here's what I've been doing to paginate my queries:
query {
node(id: "PROJECT_ID") {
... on ProjectNext {
items(first: 100 after: CURSOR) {
pageInfo {
hasNextPage
endCursor
}
nodes {
title
fieldValues(first: 8) {
nodes {
value
}
}
content {
... on Issue {
number
labels(first: 50) {
nodes {
name
}}}}}}}}}
In my Python code I'm splicing in PROJECT_ID with a variable set to the project ID I'm referencing.
For the cursor after: CURSOR is replaced with "" initially, and then for the next page I set cursor = 'after:\\"' + response["data"]["node"]["items"]["pageInfo"]["endCursor"] + '\\"'
My full code is in the atdumpmemex module of my dump_cards utility.
The key here is to get pageInfo along with other relevant nodes, and then grab the endCursor each time hasNextPage is true so that it can be fed into the query for the next iteration.
pageInfo will look something like:
"pageInfo": {
"hasNextPage": false,
"endCursor": "Y3Vyc29yOnYyOpHOAAhOsg=="
}
At the moment the endCursor is base64 encoded cursor:v2:XYZ, but don't rely on that as GitHub have moved other IDs from being base64 encoded to other schemes.
Pagination using endCursor is the one solution. Like REST API, you cannot traverse all pages pragmatically. As you specified you can specify endCursor and traverse if there is next page

GraphQL non nested relation

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.

Resources