Sitecore GraphQL from the frontend - reactjs

I am looking for an article/example taht can help me do the following:
Run a graphql query (which runs perfectly in the Playground) through my react code
This is the code I am referring to:
export const getStaticProps : GetStaticProps = async(context)=> {
const endPoint = process.env.PREVIEW_URL as string;
const graphQLClient = new GraphQLClient(endPoint);
graphQLClient.setHeader('X-GQL-Token', process.env.PREVIEW_API as string);
const query = gql`{
item(path: "/sitecore/content/sug-containers/home/Item" language: "en"){
field(name: "imageSrc") {
... on ImageField {
id(format: "B")
name
src
}
}
}
}
}`
const data = await graphQLClient.request(query);
console.log(JSON.stringify(data, undefined, 2))
return{
props:{data}
};
}
However, no data is every returned. Props is always null.
I think my query definition is incorrect. I copied the query that runs successfully in the playground. Does anyone know what the problem could be or point me to a working example somewhere please? I have referred to this article:
https://thetombomb.com/posts/do-you-need-graphql-client
In the GraphQL playground, this is the query I use:
query {
item(path: "/sitecore/content/sug-containers/home/AvistaLogo" language: "en"){
field(name: "imageSrc") {
... on ImageField {
id(format: "B")
name
src
}
}
}
}
And here is the output:
{
"data": {
"item": {
"field": {
"id": "{94B0DA6A-D944-489B-B6B0-39094114F244}",
"name": "imageSrc",
"src": "/sitecore/shell/-/media/Images/Logos/logo.svg"
}
}
}
}

Related

Mocked Apollo Provider with React testing library is not returning data

I've been trying to fix this problem for a couple days and I'm still at a loss.
I have a React app that uses Apollo Client and I want to test one component with the React testing library. Omitting all the irrelevant details, my main file code looks like that:
const ComponentToTest = () => {
...
const { data, loading } = useComponentRespQuery({
variables: {
id: idValue
},
skip: !idValue
});
if (loading) {
return <>Loading</>;
}
...
}
And the test is written like that:
const componentRender = (mockGraphQLData: any, initialEntry: string = "") => render(
<MemoryRouter initialEntries={[initialEntry]}>
<MockedProvider mocks={[ mockGraphQLData ]} addTypename={false}>
<ComponentToTest />
</MockedProvider>
</MemoryRouter>
);
describe("ComponenToTest", () => {
it("should render a component to test", async() => {
componentRender(zoneMock);
const placeHolderValues = await screen.findByText(/Bla/i);
expect(placeHolderValues).toBeInTheDocument();
});
...
}
Where componentRespDocument is equal to
query GetResp($id: ID!) {
resp(id: $id) {
id
name
description
controls {
id
name
}
}
And my mock is written like that
export const componentRespMock = {
request: {
query: componentRespDocument
},
result: {
data: {
resp: {
id: "ID",
name: "NAME",
description: "DESCRIPTION",
controls: [
{
id: "CTRL_2",
name: "Second control"
}
]
}
}
}
};
I can confidently say that this way of testing worked before in my codebase. I found one way to make Apollo return the right value while testing, and it was to comment out all the code in useComponentRespQuery.
Anybody faced it before and knows how to fix it?
It is a bit hard to say without knowing what's under the hood in MockedProvider provider. However, in my experience with mocks they should always match (1:1), especially if it works when you comment out { variables: { id: idValue }, skip: !idValue } inside useComponentRespQuery.
I would suggest double checking zoneMock to make sure that it matches what you expect

How to get Apollo gql codgen to work with frontend nextJS

I am using nextJS, I want my front end react queries with apollo to be typed out, but no configuration is working. I get an unknown error on my query when I use import {gql} from src/__generated__/gql and the following message when I hover over gql():
The query argument is unknown! Please regenerate the types
My question is do I need to do something different because I am using nextJS? I want to be able to use TypeScript with Apollo Client code gendocs so my gql queries will be typed
My entire pothos schema is in my pages/api/index.ts file (I do not yet know how to spread this code out into multiple files)
Example Query:
const CREATED_EVENT_QUERY = gql(`
query EventById($id: mongoId!) {
eventById(id: $id) {
_id
name
description
location{
coordinates
}
date
eventApplicants{
name
userId
weight
}
link
weights{
weight
spotsAvailable{
name
userId
}
}
}
}
`);
// Apollo Query
const { loading, error, data } = useQuery(CREATED_EVENT_QUERY, {
variables: {
id: params.id
}
});
I have tried the following configurations:
Apollos recommendation
Link Above
import { CodegenConfig } from '#graphql-codegen/cli';
const config: CodegenConfig = {
schema: 'http://localhost:3000/api',
documents: ['*.ts'],
generates: {
'./src/__generated__/': {
preset: 'client',
plugins: [],
presetConfig: {
gqlTagName: 'gql',
}
}
},
ignoreNoDocuments: true,
};
export default config;
the guilds nextJS recomendation
import type { CodegenConfig } from '#graphql-codegen/cli'
const config: CodegenConfig = {
// ...
generates: {
'path/to/file.ts': {
plugins: ['typescript', 'typescript-operations', 'typescript-react-apollo'],
config: {
reactApolloVersion: 3
}
}
}
}
export default config
combination of the two
import { CodegenConfig } from '#graphql-codegen/cli';
const config: CodegenConfig = {
schema: 'http://localhost:3000/api',
documents: ['*.ts'],
generates: {
'pages/api/index.ts': {
plugins: ['typescript', 'typescript-operations', 'typescript-react-apollo'],
config: {
reactApolloVersion: 3
}
}
},
ignoreNoDocuments: true,
};
export default config;

Passing Arguments to GraphQL with Next.JS and Apollo

A lot of this is very new to me since I have been a PHP developer for so long.
I am having a couple of issues that I know are easy to fix. I just have limited experience and am learning.
I cannot seem to pass the argument $token_id. I am using next JS, and I just want to take the number on the [id].js page, and pass it as the token ID.
I can't seem to get data from traitType, which is an object named "traits" which has an array of objects inside of it.
export async function getStaticProps(context) {
const client = new ApolloClient({
uri: 'http://localhost:3000/api/graphql',
cache: new InMemoryCache()
});
const token_id = String(context.params.id)
const { data } = await client.query({
query: gql`
query myQuery($token_id: String!) {
getData(token_id: $token_id) {
token_id
name
}
}
`
},{ variables: { token_id } });
props: {
data: data,
}
}
export async function getStaticPaths() {
return {
paths: [], //indicates that no page needs be created at build time
fallback: 'blocking' //indicates the type of fallback
}
}
My Type Definition
type Blah {
token_id: String
name: String
#traits: [traitType] #TODO: returns nothing since data is array
}
type traitType {
trait_type: String
value: String
}
I have to hard code the token
getData(token_id: "6") {
token_id
name
traits {
trait_type
}
}
I have tried several variations in the graphql query
query getDataQuery($token_id: String! = "6") {
getData(token_id: $token_id) {
Returns Null on traits, and $token id is null, and nothing is found
"traits": [
{
"trait_type": null,
"value": null
}
],
And my JSON from mongo db is an array with an object.
"traits" : [
{
"trait_type" : "birthday",
"value" : 1627423029.0,
}
]
I can post more than just fragments of code. Sorry for the formatting.

How to set a limit for nested field in AWS amplify DynamoDB schema on my React App?

I am using AWS Amplify and DynamoDB and I would like to set a limit from a the nested field "medias". This is the query on AppSync to get only 4 items :
{
getUser(id: "xxx4e5b-9704-564xxx") {
medias(limit: 4) {
items {
title
}
}
}
}
It seems to work, this is the result I have on AppSync :
{
"data": {
"getUser": {
"medias": {
[
{
"title": "Test 1"
},
{
"title": "Test Audio"
},
{
"title": "Test Guitare"
},
{
"title": "Test lien"
}
],
}
}
}
}
I would like to know how to do this query on my React application ? I tried this but it didn't work (I should have 4 media items in my response but I get more) :
const query = await API.graphql(
graphqlOperation(getUser, {
id: userID,
medias: { limit: 4 }
})
)
I didn't find any help on amplify doc. Could you please help me ?
It's an issue with the way you pass the parameters in to graphqlOperation which takes in a query and the options for that query only.
const limit = 4;
// whatever you want to filter by
const filter = {id: userID};
const result = await API.graphql(
graphqlOperation(getUser, {filter, limit})
);

Handling Graphql Mutation update, cache read and writeQuery, if the query is dynamic?

Doing nightlife app on freecodecamp https://learn.freecodecamp.org/coding-interview-prep/take-home-projects/build-a-nightlife-coordination-app/
I am trying to implement 'Go' button, similarly 'Like' button on Youtube or Instagram. Users click the button the number(counting how many users go) goes up meaning users will go there and click again, it revokes, the number decreases, users will not go there.
It seems like working well except the issue, I have to refresh the page and then, the number has increased or decreased and throws the error like below so:
Invariant Violation: Can't find field getBars({}) on object {
"getBars({\"location\":\"vancouver\"})": [
{
"type": "id",
"generated": false,
"id": "Bar:uNgTjA9ADe_6LWby20Af8g",
"typename": "Bar"
},
{
"type": "id",
"generated": false,
"id": "Bar:CwL5jwXhImT_7K5IB7mOvA",
"typename": "Bar"
},
{
"type": "id",
"generated": false,
"id": "Bar:mdt1tLbkZcOS2CsEbVF9Xg",
"typename": "Bar"
},
.
.
.
I am assuming handling update function will fix this issue but unlike the example from Apollo documentation:
// GET_TODOS is not dynamic query
// nothing to pass as variables to fetch TODO list
<Mutation
mutation={ADD_TODO}
update={(cache, { data: { addTodo } }) => {
const { todos } = cache.readQuery({ query: GET_TODOS });
cache.writeQuery({
query: GET_TODOS,
data: { todos: todos.concat([addTodo]) },
});
}}
>
My query is dynamic:
// I have to pass location variable, otherwise it won't fetch anything.
const GET_BARS_QUERY = gql`
query getBars($location: String!) {
getBars(location: $location) {
id
name
url
rating
price
image_url
goings {
username
}
goingCount
}
}
`;
I believe I might need to handle to provide location using readQuery and writeQury but not too sure what I should do.
Here's my code:
const GoButton = ({ user, bar }) => {
const { token } = user;
const { id, goings, goingCount } = bar;
const [userGoes] = useMutation(GO_MUTATION, {
variables: { yelp_id: id },
update(proxy, result) {
const data = proxy.readQuery({
query: GET_BARS_QUERY
});
data.getBars = [result.userGoes, ...data.getBars];
proxy.writeQuery({ query: GET_BARS_QUERY, data });
}
});
return (
<Button onClick={userGoes}>
Go {goingCount}
</Button>
);
};
const GO_MUTATION = gql`
mutation go($yelp_id: String!) {
go(yelp_id: $yelp_id) {
id
goings {
id
username
}
goingCount
}
}
`;
export default GoButton;
Full code here https://github.com/footlessbird/Nightlife-Coordination-App
when you read/write the getBars query, you need to pass the location as a variable
const [userGoes] = useMutation(GO_MUTATION, {
variables: { yelp_id: id },
update(proxy, result) {
const data = proxy.readQuery({
query: GET_BARS_QUERY,
variables: {
location: 'New York'
}
});
data.getBars = [result.userGoes, ...data.getBars];
proxy.writeQuery({ query: GET_BARS_QUERY, data,
variables: {
location: 'New York'
}
});
}
});

Resources