Popular New Releases in Apollo
apollo-client
3.5.x
graphql-yoga
@graphql-yoga/node@2.3.0
vue-apollo
apollo-tooling
GraphQLite
1.2.0
Popular Libraries in Apollo
by apollographql typescript
17556 MIT
:rocket: A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server.
by apollographql typescript
12509 MIT
🌍 Spec-compliant and production ready JavaScript GraphQL server that lets you develop in a schema-first way. Built for Express, Connect, Hapi, Koa, and more.
by howtographql typescript
7982 MIT
The Fullstack Tutorial for GraphQL
by apollographql javascript
6935 MIT
:recycle: React integration for Apollo Client
by dotansimha typescript
6775 MIT
🧘 Rewrite of a fully-featured GraphQL Server with focus on easy setup, performance & great developer experience. The core of Yoga implements W3C Fetch API and can run/deploy on any JS environment.
by prisma-labs typescript
6351 MIT
🧘 Fully-featured GraphQL Server with focus on easy setup, performance & great developer experience
by vuejs javascript
5388 MIT
🚀 Apollo/GraphQL integration for VueJS
by learnapollo typescript
5284 MIT
👩🏻🏫 Learn Apollo - A hands-on tutorial for Apollo GraphQL Client (created by Graphcool)
by relatedcode swift
4164 MIT
Open source, native iOS Messenger, with realtime chat conversations (full offline support).
Trending New libraries in Apollo
by paljs typescript
496 MIT
Prisma tools to help you generate CRUD system for GraphQL servers
by apollographql typescript
436 NOASSERTION
🌐 Build and scale a single data graph across multiple services with Apollo's federation gateway.
by yamalight javascript
306 MIT
Minimalistic GraphQL framework
by apollographql rust
285 NOASSERTION
✨🤖 🐶 the new CLI for Apollo
by ghoshnirmalya typescript
224 MIT
:art: Boilerplate for building applications using Hasura and Next.js
by oslabs-beta typescript
164 MIT
Portara directive is a rate limiter / throttler for GraphQL
by correttojs typescript
155
Autogenerate apollo code for nextjs ssr
by ysugimoto go
135 MIT
A protoc plugin that generates graphql execution code from Protocol Buffers.
by hasura typescript
130
A movies app using Hasura and gqless
Top Authors in Apollo
1
19 Libraries
48605
2
18 Libraries
3415
3
7 Libraries
461
4
6 Libraries
2427
5
6 Libraries
1593
6
6 Libraries
319
7
5 Libraries
232
8
5 Libraries
126
9
5 Libraries
167
10
5 Libraries
148
1
19 Libraries
48605
2
18 Libraries
3415
3
7 Libraries
461
4
6 Libraries
2427
5
6 Libraries
1593
6
6 Libraries
319
7
5 Libraries
232
8
5 Libraries
126
9
5 Libraries
167
10
5 Libraries
148
Trending Kits in Apollo
No Trending Kits are available at this moment for Apollo
Trending Discussions on Apollo
Vue 3, GraphQL, Apollo - How to re-render query when cache changes?
Apollo Client "Named export 'remove' not found"
Duplicate active queries in Apollo Client Devtools
I need help on 'Cannot find namespace Kind' issue
NestJS GraphQL subscriptions not working with `graphql-ws`
AWS Graphql lambda query
How to use Graphql typescript types in react
Testing React Component with React Router V6
Error: GraphQL error: Field 'metafieldsSet' doesn't exist on type 'Mutation' - Shopify GraphQL error
Error: You must `await server.start()` before calling `server.applyMiddleware()`
QUESTION
Vue 3, GraphQL, Apollo - How to re-render query when cache changes?
Asked 2022-Mar-31 at 11:33I would like to know how to build Vue 3 Apollo apps with queries and mutations. I'm familiar with react useQuery
hook. It re-renders the component whenever the cached data has been changed (by mutations).
I have tried:
- useQuery (https://v4.apollo.vuejs.org/api/use-query.html)
- ApolloQuery (https://v4.apollo.vuejs.org/guide-components/query.html)
In all cases it just loads the data once and doesnt react to cache data changes.
I undestand that I can build own setup by Apollo client or refetch the queries. I can even invalidate components by its keys. This is not really as elegant as the React useQuery
hook is.
I was curious whether there is any ready-made solution and the best practice for smooth graphql operations in Vue 3.
ANSWER
Answered 2022-Mar-31 at 11:33I have misconfigured the schema and cache update. So the answer is that it works well.
For example:
1<template>
2 <div v-if="loading">...loading</div>
3 <div v-else-if="error">{{ error.message }}</div>
4 <div v-else>{{value}}</div>
5</template>
6
7<script setup lang="ts">
8 import gql from "graphql-tag";
9 import { GetValueQuery } from "./ValueComponent.generated";
10 import { useQuery, useResult } from "@vue/apollo-composable";
11
12 const GetValue = gql`
13 query getValue {
14 value
15 }
16 `;
17
18 function useGetValue() {
19 const { result, loading, error } =
20 useQuery<GetValueQuery>(GetValue);
21 const value = useResult(result, null, (data) => data.value);
22 return { value, loading, error };
23 }
24
25 const { value, loading, error } = useGetScans();
26</script>
27
28
Works the described way - the template is re-rendered once data cache changed (by a mutation with the proper result set or by its update
function)
So it is not valid question, the bug was in the implementation of cache policy on my side.
QUESTION
Apollo Client "Named export 'remove' not found"
Asked 2022-Mar-12 at 09:45I'm attempting to create an apollo client
plugin for a Nuxt 3
application. It's currently throwing an error regarding a package called ts-invariant
:
1file:///Users/[my name]/Repositories/[project]/node_modules/@apollo/client/utilities/globals/fix-graphql.js:1
2import { remove } from "ts-invariant/process/index.js";
3 ^^^^^^
4SyntaxError: Named export 'remove' not found. The requested module 'ts-invariant/process/index.js' is a CommonJS module, which may not support all module.exports as named exports.
5CommonJS modules can always be imported via the default export, for example using:
6
7import pkg from 'ts-invariant/process/index.js';
8const { remove } = pkg;
9
10 at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21)
11 at async ModuleJob.run (node:internal/modules/esm/module_job:181:5)
12 at async Promise.all (index 0)
13 at async ESMLoader.import (node:internal/modules/esm/loader:281:24)
14 at async __instantiateModule__ (file:///Users/[my name]/Repositories/[project]/.nuxt/dist/server/server.mjs:4550:3)
15[vite dev] Error loading external "/Users/[my name]/Repositories/[project]/node_modules/@apollo/client/core/index.js".
16 at file://./.nuxt/dist/server/server.mjs:3170:289
17 at async __instantiateModule__ (file://./.nuxt/dist/server/server.mjs:4550:3)
18
I feel like I know enough about this error to know it has something to do with how Nuxt 3 deals with ESM, but I can't be for certain.
Here's the nuxt plugin:
plugins/apollo-client.js
1file:///Users/[my name]/Repositories/[project]/node_modules/@apollo/client/utilities/globals/fix-graphql.js:1
2import { remove } from "ts-invariant/process/index.js";
3 ^^^^^^
4SyntaxError: Named export 'remove' not found. The requested module 'ts-invariant/process/index.js' is a CommonJS module, which may not support all module.exports as named exports.
5CommonJS modules can always be imported via the default export, for example using:
6
7import pkg from 'ts-invariant/process/index.js';
8const { remove } = pkg;
9
10 at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21)
11 at async ModuleJob.run (node:internal/modules/esm/module_job:181:5)
12 at async Promise.all (index 0)
13 at async ESMLoader.import (node:internal/modules/esm/loader:281:24)
14 at async __instantiateModule__ (file:///Users/[my name]/Repositories/[project]/.nuxt/dist/server/server.mjs:4550:3)
15[vite dev] Error loading external "/Users/[my name]/Repositories/[project]/node_modules/@apollo/client/core/index.js".
16 at file://./.nuxt/dist/server/server.mjs:3170:289
17 at async __instantiateModule__ (file://./.nuxt/dist/server/server.mjs:4550:3)
18import { defineNuxtPlugin } from "#app"
19import { ApolloClient, InMemoryCache } from "@apollo/client/core"
20import { DefaultApolloClient } from "@vue/apollo-composable"
21
22export default defineNuxtPlugin((nuxtApp) => {
23 const config = useRuntimeConfig()
24 const apolloClient = new ApolloClient({
25 uri: config.PUBLIC_API_ENDPOINT,
26 cache: new InMemoryCache(),
27 })
28 nuxtApp.vueApp.provide(DefaultApolloClient, apolloClient)
29})
30
In a normal scenario, I might use the nuxt-apollo community module, but it is currently afk regarding a nuxt 3
port, so a plugin it is.
Here's some documentation I relied on for my plugin:
https://v4.apollo.vuejs.org/guide-composable/setup.html#vue-3
https://v3.nuxtjs.org/docs/directory-structure/plugins
ANSWER
Answered 2022-Jan-07 at 01:52Solved by including @apollo/client
and ts-invariant/process
into the nuxt build transpile like so:
1file:///Users/[my name]/Repositories/[project]/node_modules/@apollo/client/utilities/globals/fix-graphql.js:1
2import { remove } from "ts-invariant/process/index.js";
3 ^^^^^^
4SyntaxError: Named export 'remove' not found. The requested module 'ts-invariant/process/index.js' is a CommonJS module, which may not support all module.exports as named exports.
5CommonJS modules can always be imported via the default export, for example using:
6
7import pkg from 'ts-invariant/process/index.js';
8const { remove } = pkg;
9
10 at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21)
11 at async ModuleJob.run (node:internal/modules/esm/module_job:181:5)
12 at async Promise.all (index 0)
13 at async ESMLoader.import (node:internal/modules/esm/loader:281:24)
14 at async __instantiateModule__ (file:///Users/[my name]/Repositories/[project]/.nuxt/dist/server/server.mjs:4550:3)
15[vite dev] Error loading external "/Users/[my name]/Repositories/[project]/node_modules/@apollo/client/core/index.js".
16 at file://./.nuxt/dist/server/server.mjs:3170:289
17 at async __instantiateModule__ (file://./.nuxt/dist/server/server.mjs:4550:3)
18import { defineNuxtPlugin } from "#app"
19import { ApolloClient, InMemoryCache } from "@apollo/client/core"
20import { DefaultApolloClient } from "@vue/apollo-composable"
21
22export default defineNuxtPlugin((nuxtApp) => {
23 const config = useRuntimeConfig()
24 const apolloClient = new ApolloClient({
25 uri: config.PUBLIC_API_ENDPOINT,
26 cache: new InMemoryCache(),
27 })
28 nuxtApp.vueApp.provide(DefaultApolloClient, apolloClient)
29})
30 // nuxt.config.js
31 // ...
32 build: {
33 postcss: {
34 postcssOptions: require('./postcss.config.js')
35 },
36 transpile: [
37 '@apollo/client',
38 'ts-invariant/process',
39 ],
40 },
41 // ...
42
QUESTION
Duplicate active queries in Apollo Client Devtools
Asked 2022-Feb-28 at 17:33I’m using React with Apollo Client 3 and Hasura as a GraphQL server.
The component ProductList
use the get_products
query once.
Then two exact copies of this query are memorized in the Apollo Cache as shown in the Apollo DevTools.
My question is - Why two identical queries get generated in the cache instead of one?
Apollo DevTools results
My code
1import {
2 ApolloClient,
3 ApolloProvider,
4 InMemoryCache,
5 HttpLink,
6 gql,
7 useQuery,
8} from "@apollo/client";
9
10const client = new ApolloClient({
11 link: new HttpLink({
12 uri: "http://localhost:8080/v1/graphql",
13 }),
14 cache: new InMemoryCache(),
15});
16
17function App() {
18 return (
19 <div className="App">
20 <ApolloProvider client={client}>
21 <ProductList />
22 </ApolloProvider>
23 </div>
24 );
25}
26
27const ProductList = () => {
28 const GET_PRODUCTS = gql`
29 query get_products {
30 product {
31 id
32 name
33 __typename
34 }
35 }
36 `;
37
38 const { loading, error, data } = useQuery(GET_PRODUCTS);
39 if (loading) return <p>Loading ...</p>;
40 if (error) return <p> {error.message}</p>;
41 return (
42 <>
43 <h1>ProductList</h1>
44 <ul>
45 {data?.product.map((product: any) => {
46 return <li key={product.id}>{product.name}</li>;
47 })}
48 </ul>
49 </>
50 );
51};
52
53export default App;
54
ANSWER
Answered 2022-Feb-28 at 17:33This is basically a duplicate of Apollo Client what are active queries?
The main concept is that Active Queries represents the queries that are running inside of mounted components in your React application. It doesn't mean that the data is cached twice, it means that there are two places in your application that rely on the results of this query.
If the results of the query in cache are updated both places will automatically get the data updates.
QUESTION
I need help on 'Cannot find namespace Kind' issue
Asked 2022-Feb-21 at 19:38I just updated NestJs to latest (8.3.1) from 7.5, solved the issues that popped out, but I cannot get rid of one of them.
The full error:
1node_modules/@apollo/federation/dist/composition/utils.d.ts:43:316 - error TS2503: Cannot find namespace 'Kind'.
2
Although Kind is a constant imported from the GraphQl module, it seems it does not recognize it. Or maybe is a typescript issue?
Any help would be greatly appreciated.
ANSWER
Answered 2022-Feb-19 at 07:45There were other libraries that were outdated, after I updated all of them, the error disappeared.
QUESTION
NestJS GraphQL subscriptions not working with `graphql-ws`
Asked 2022-Feb-21 at 12:01I'm trying to upgrade our NestJS GraphQL subscriptions server to utilize graphql-ws
rather than the current subscriptions-transport-ws
(as suggested by the NestJS documentation).
I upgraded the NestJS version to
1 "@nestjs/core": "^8.0.6",
2 "@nestjs/graphql": "^9.0.4",
3 "@nestjs/platform-express": "^8.0.6",
4 "graphql": "^15.5.3",
5 "graphql-tools": "^8.2.0",
6 "apollo-server-express": "^3.3.0",
7
And after, I added the subscriptions
option to the App.Module
:
1 "@nestjs/core": "^8.0.6",
2 "@nestjs/graphql": "^9.0.4",
3 "@nestjs/platform-express": "^8.0.6",
4 "graphql": "^15.5.3",
5 "graphql-tools": "^8.2.0",
6 "apollo-server-express": "^3.3.0",
7 GraphQLModule.forRoot({
8 autoSchemaFile: true,
9 sortSchema: true,
10 playground: true,
11 installSubscriptionHandlers: true,
12 subscriptions: {
13 'graphql-ws': true
14 },
15 }),
16
However when I subscribe (in playground) to a previously working subscription, I get:
1 "@nestjs/core": "^8.0.6",
2 "@nestjs/graphql": "^9.0.4",
3 "@nestjs/platform-express": "^8.0.6",
4 "graphql": "^15.5.3",
5 "graphql-tools": "^8.2.0",
6 "apollo-server-express": "^3.3.0",
7 GraphQLModule.forRoot({
8 autoSchemaFile: true,
9 sortSchema: true,
10 playground: true,
11 installSubscriptionHandlers: true,
12 subscriptions: {
13 'graphql-ws': true
14 },
15 }),
16{
17 "error": "Could not connect to websocket endpoint ws://localhost:8880/graphql. Please check if the endpoint url is correct."
18}
19
And in the console I get:
1 "@nestjs/core": "^8.0.6",
2 "@nestjs/graphql": "^9.0.4",
3 "@nestjs/platform-express": "^8.0.6",
4 "graphql": "^15.5.3",
5 "graphql-tools": "^8.2.0",
6 "apollo-server-express": "^3.3.0",
7 GraphQLModule.forRoot({
8 autoSchemaFile: true,
9 sortSchema: true,
10 playground: true,
11 installSubscriptionHandlers: true,
12 subscriptions: {
13 'graphql-ws': true
14 },
15 }),
16{
17 "error": "Could not connect to websocket endpoint ws://localhost:8880/graphql. Please check if the endpoint url is correct."
18}
19WebSocket protocol error occured. It was most likely caused due to an unsupported subprotocol "graphql-ws" requested by the client. graphql-ws implements exclusively the "graphql-transport-ws" subprotocol, please make sure that the client implements it too.
20
Things I have tried:
- Adding the
graphql-ws
package - Upgrading the NestJS version again
- Removing the
installSubscriptionHandlers
option from config - Setting
graphql-ws
configs instead of passingtrue
- Using the
WebSocket Test Client
Google Chrome extension instead of Playground
But none have worked. Sorry for the long post. How can I fix this?
ANSWER
Answered 2021-Sep-16 at 13:35At the time of release of Apollo Server 3, the protocol used in the graphql-ws library is not yet supported by GraphQL Playground or Apollo Explorer.
see here
It's only advisable to use graphql-ws if interacting with subscriptions via playground is not of much use to you and you're okay interacting with subscriptions solely from your own client that has been setup to use graphql-ws.
To setup your client to use graphql-ws with Apollo. see here.
QUESTION
AWS Graphql lambda query
Asked 2022-Jan-09 at 17:12I am not using AWS AppSync for this app. I have created Graphql schema, I have made my own resolvers. For each create, query, I have made each Lambda functions. I used DynamoDB Single table concept and it's Global secondary indexes.
It was ok for me, to create an Book item. In DynamoDB, the table looks like this: .
I am having issue with the return Graphql queries. After getting the Items
from DynamoDB table, I have to use Map function then return the Items
based on Graphql type
. I feel like this is not efficient way to do that. Idk the best way query data. Also I am getting null both author and authors query.
This is my gitlab-branch.
This is my Graphql Schema
1import { gql } from 'apollo-server-lambda';
2
3const typeDefs = gql`
4 enum Genre {
5 adventure
6 drama
7 scifi
8 }
9
10 enum Authors {
11 AUTHOR
12 }
13
14 # Root Query - all the queries supported by the schema
15
16 type Query {
17 """
18 All Authors query
19 """
20 authors(author: Authors): [Author]
21 books(book: String): [Book]
22 }
23
24 # Root Mutation - all the mutations supported by the schema
25 type Mutation {
26 createBook(input: CreateBook!): Book
27 }
28
29 """
30 One Author can have many books
31 """
32 type Author {
33 id: ID!
34 authorName: String
35 book: [Book]!
36 }
37
38 """
39 Book Schema
40 """
41 type Book {
42 id: ID!
43 name: String
44 price: String
45 publishingYear: String
46 publisher: String
47 author: [Author]
48 description: String
49 page: Int
50 genre: [Genre]
51 }
52
53 input CreateBook {
54 name: String
55 price: String
56 publishingYear: String
57 publisher: String
58 author: [CreateAuthor]
59 description: String
60 page: Int
61 genre: [Genre]
62 }
63
64 input CreateAuthor {
65 authorName: String!
66 }
67`;
68export default typeDefs;
This is I created the Book Item
1import { gql } from 'apollo-server-lambda';
2
3const typeDefs = gql`
4 enum Genre {
5 adventure
6 drama
7 scifi
8 }
9
10 enum Authors {
11 AUTHOR
12 }
13
14 # Root Query - all the queries supported by the schema
15
16 type Query {
17 """
18 All Authors query
19 """
20 authors(author: Authors): [Author]
21 books(book: String): [Book]
22 }
23
24 # Root Mutation - all the mutations supported by the schema
25 type Mutation {
26 createBook(input: CreateBook!): Book
27 }
28
29 """
30 One Author can have many books
31 """
32 type Author {
33 id: ID!
34 authorName: String
35 book: [Book]!
36 }
37
38 """
39 Book Schema
40 """
41 type Book {
42 id: ID!
43 name: String
44 price: String
45 publishingYear: String
46 publisher: String
47 author: [Author]
48 description: String
49 page: Int
50 genre: [Genre]
51 }
52
53 input CreateBook {
54 name: String
55 price: String
56 publishingYear: String
57 publisher: String
58 author: [CreateAuthor]
59 description: String
60 page: Int
61 genre: [Genre]
62 }
63
64 input CreateAuthor {
65 authorName: String!
66 }
67`;
68export default typeDefs;import AWS from 'aws-sdk';
69import { v4 } from 'uuid';
70import { CreateBook } from '../../generated/schema';
71
72async function createBook(_: unknown, { input }: { input: CreateBook }) {
73 const dynamoDb = new AWS.DynamoDB.DocumentClient();
74 const id = v4();
75
76 const authorsName =
77 input.author &&
78 input.author.map(function (item) {
79 return item['authorName'];
80 });
81
82 const params = {
83 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
84 Item: {
85 PK: `AUTHOR`,
86 SK: `AUTHORS#${id}`,
87 GSI1PK: `BOOKS`,
88 GSI1SK: `BOOK#${input.name}`,
89 name: input.name,
90 author: authorsName,
91 price: input.price,
92 publishingYear: input.publishingYear,
93 publisher: input.publisher,
94 page: input.page,
95 description: input.description,
96 genre: input.genre,
97 },
98 };
99
100 await dynamoDb.put(params).promise();
101
102 return {
103 ...input,
104 id,
105 };
106}
107
108export default createBook;
This is how query the All Book
1import { gql } from 'apollo-server-lambda';
2
3const typeDefs = gql`
4 enum Genre {
5 adventure
6 drama
7 scifi
8 }
9
10 enum Authors {
11 AUTHOR
12 }
13
14 # Root Query - all the queries supported by the schema
15
16 type Query {
17 """
18 All Authors query
19 """
20 authors(author: Authors): [Author]
21 books(book: String): [Book]
22 }
23
24 # Root Mutation - all the mutations supported by the schema
25 type Mutation {
26 createBook(input: CreateBook!): Book
27 }
28
29 """
30 One Author can have many books
31 """
32 type Author {
33 id: ID!
34 authorName: String
35 book: [Book]!
36 }
37
38 """
39 Book Schema
40 """
41 type Book {
42 id: ID!
43 name: String
44 price: String
45 publishingYear: String
46 publisher: String
47 author: [Author]
48 description: String
49 page: Int
50 genre: [Genre]
51 }
52
53 input CreateBook {
54 name: String
55 price: String
56 publishingYear: String
57 publisher: String
58 author: [CreateAuthor]
59 description: String
60 page: Int
61 genre: [Genre]
62 }
63
64 input CreateAuthor {
65 authorName: String!
66 }
67`;
68export default typeDefs;import AWS from 'aws-sdk';
69import { v4 } from 'uuid';
70import { CreateBook } from '../../generated/schema';
71
72async function createBook(_: unknown, { input }: { input: CreateBook }) {
73 const dynamoDb = new AWS.DynamoDB.DocumentClient();
74 const id = v4();
75
76 const authorsName =
77 input.author &&
78 input.author.map(function (item) {
79 return item['authorName'];
80 });
81
82 const params = {
83 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
84 Item: {
85 PK: `AUTHOR`,
86 SK: `AUTHORS#${id}`,
87 GSI1PK: `BOOKS`,
88 GSI1SK: `BOOK#${input.name}`,
89 name: input.name,
90 author: authorsName,
91 price: input.price,
92 publishingYear: input.publishingYear,
93 publisher: input.publisher,
94 page: input.page,
95 description: input.description,
96 genre: input.genre,
97 },
98 };
99
100 await dynamoDb.put(params).promise();
101
102 return {
103 ...input,
104 id,
105 };
106}
107
108export default createBook;import AWS from 'aws-sdk';
109
110async function books(_: unknown, input: { book: string }) {
111 const dynamoDb = new AWS.DynamoDB.DocumentClient();
112
113 const params = {
114 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
115 IndexName: 'GSI1',
116 KeyConditionExpression: 'GSI1PK = :hkey',
117 ExpressionAttributeValues: {
118 ':hkey': `${input.book}`,
119 },
120 };
121
122 const { Items } = await dynamoDb.query(params).promise();
123
124 const allBooks = // NEED TO MAP THE FUNcTION THEN RETURN THE DATA BASED ON GRAPHQL //QUERIES.
125 Items &&
126 Items.map((i) => {
127 const genre = i.genre.filter((i) => i);
128 return {
129 name: i.name,
130 author: i.author,
131 genre,
132 };
133 });
134
135 return allBooks;
136}
137
138export default books;
1import { gql } from 'apollo-server-lambda';
2
3const typeDefs = gql`
4 enum Genre {
5 adventure
6 drama
7 scifi
8 }
9
10 enum Authors {
11 AUTHOR
12 }
13
14 # Root Query - all the queries supported by the schema
15
16 type Query {
17 """
18 All Authors query
19 """
20 authors(author: Authors): [Author]
21 books(book: String): [Book]
22 }
23
24 # Root Mutation - all the mutations supported by the schema
25 type Mutation {
26 createBook(input: CreateBook!): Book
27 }
28
29 """
30 One Author can have many books
31 """
32 type Author {
33 id: ID!
34 authorName: String
35 book: [Book]!
36 }
37
38 """
39 Book Schema
40 """
41 type Book {
42 id: ID!
43 name: String
44 price: String
45 publishingYear: String
46 publisher: String
47 author: [Author]
48 description: String
49 page: Int
50 genre: [Genre]
51 }
52
53 input CreateBook {
54 name: String
55 price: String
56 publishingYear: String
57 publisher: String
58 author: [CreateAuthor]
59 description: String
60 page: Int
61 genre: [Genre]
62 }
63
64 input CreateAuthor {
65 authorName: String!
66 }
67`;
68export default typeDefs;import AWS from 'aws-sdk';
69import { v4 } from 'uuid';
70import { CreateBook } from '../../generated/schema';
71
72async function createBook(_: unknown, { input }: { input: CreateBook }) {
73 const dynamoDb = new AWS.DynamoDB.DocumentClient();
74 const id = v4();
75
76 const authorsName =
77 input.author &&
78 input.author.map(function (item) {
79 return item['authorName'];
80 });
81
82 const params = {
83 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
84 Item: {
85 PK: `AUTHOR`,
86 SK: `AUTHORS#${id}`,
87 GSI1PK: `BOOKS`,
88 GSI1SK: `BOOK#${input.name}`,
89 name: input.name,
90 author: authorsName,
91 price: input.price,
92 publishingYear: input.publishingYear,
93 publisher: input.publisher,
94 page: input.page,
95 description: input.description,
96 genre: input.genre,
97 },
98 };
99
100 await dynamoDb.put(params).promise();
101
102 return {
103 ...input,
104 id,
105 };
106}
107
108export default createBook;import AWS from 'aws-sdk';
109
110async function books(_: unknown, input: { book: string }) {
111 const dynamoDb = new AWS.DynamoDB.DocumentClient();
112
113 const params = {
114 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
115 IndexName: 'GSI1',
116 KeyConditionExpression: 'GSI1PK = :hkey',
117 ExpressionAttributeValues: {
118 ':hkey': `${input.book}`,
119 },
120 };
121
122 const { Items } = await dynamoDb.query(params).promise();
123
124 const allBooks = // NEED TO MAP THE FUNcTION THEN RETURN THE DATA BASED ON GRAPHQL //QUERIES.
125 Items &&
126 Items.map((i) => {
127 const genre = i.genre.filter((i) => i);
128 return {
129 name: i.name,
130 author: i.author,
131 genre,
132 };
133 });
134
135 return allBooks;
136}
137
138export default books;import AWS from 'aws-sdk';
139import { Author, Authors } from '../../generated/schema';
140
141async function authors(
142 _: unknown,
143 input: { author: Authors }
144): Promise<Author> {
145 const dynamoDb = new AWS.DynamoDB.DocumentClient();
146
147 const params = {
148 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
149 KeyConditionExpression: 'PK = :hkey',
150 ExpressionAttributeValues: {
151 ':hkey': `${input.author}`,
152 },
153 };
154
155 const { Items } = await dynamoDb.query(params).promise();
156
157 console.log({ Items }); // I can see the data but don't know how to returns the data like this below type without using map function
158
159 // type Author {
160 // id: ID!
161 // authorName: String
162 // book: [Book]!
163 // }
164
165 return Items; // return null in Graphql play ground.
166}
167
168export default authors;
Edit: current resolver map
1import { gql } from 'apollo-server-lambda';
2
3const typeDefs = gql`
4 enum Genre {
5 adventure
6 drama
7 scifi
8 }
9
10 enum Authors {
11 AUTHOR
12 }
13
14 # Root Query - all the queries supported by the schema
15
16 type Query {
17 """
18 All Authors query
19 """
20 authors(author: Authors): [Author]
21 books(book: String): [Book]
22 }
23
24 # Root Mutation - all the mutations supported by the schema
25 type Mutation {
26 createBook(input: CreateBook!): Book
27 }
28
29 """
30 One Author can have many books
31 """
32 type Author {
33 id: ID!
34 authorName: String
35 book: [Book]!
36 }
37
38 """
39 Book Schema
40 """
41 type Book {
42 id: ID!
43 name: String
44 price: String
45 publishingYear: String
46 publisher: String
47 author: [Author]
48 description: String
49 page: Int
50 genre: [Genre]
51 }
52
53 input CreateBook {
54 name: String
55 price: String
56 publishingYear: String
57 publisher: String
58 author: [CreateAuthor]
59 description: String
60 page: Int
61 genre: [Genre]
62 }
63
64 input CreateAuthor {
65 authorName: String!
66 }
67`;
68export default typeDefs;import AWS from 'aws-sdk';
69import { v4 } from 'uuid';
70import { CreateBook } from '../../generated/schema';
71
72async function createBook(_: unknown, { input }: { input: CreateBook }) {
73 const dynamoDb = new AWS.DynamoDB.DocumentClient();
74 const id = v4();
75
76 const authorsName =
77 input.author &&
78 input.author.map(function (item) {
79 return item['authorName'];
80 });
81
82 const params = {
83 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
84 Item: {
85 PK: `AUTHOR`,
86 SK: `AUTHORS#${id}`,
87 GSI1PK: `BOOKS`,
88 GSI1SK: `BOOK#${input.name}`,
89 name: input.name,
90 author: authorsName,
91 price: input.price,
92 publishingYear: input.publishingYear,
93 publisher: input.publisher,
94 page: input.page,
95 description: input.description,
96 genre: input.genre,
97 },
98 };
99
100 await dynamoDb.put(params).promise();
101
102 return {
103 ...input,
104 id,
105 };
106}
107
108export default createBook;import AWS from 'aws-sdk';
109
110async function books(_: unknown, input: { book: string }) {
111 const dynamoDb = new AWS.DynamoDB.DocumentClient();
112
113 const params = {
114 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
115 IndexName: 'GSI1',
116 KeyConditionExpression: 'GSI1PK = :hkey',
117 ExpressionAttributeValues: {
118 ':hkey': `${input.book}`,
119 },
120 };
121
122 const { Items } = await dynamoDb.query(params).promise();
123
124 const allBooks = // NEED TO MAP THE FUNcTION THEN RETURN THE DATA BASED ON GRAPHQL //QUERIES.
125 Items &&
126 Items.map((i) => {
127 const genre = i.genre.filter((i) => i);
128 return {
129 name: i.name,
130 author: i.author,
131 genre,
132 };
133 });
134
135 return allBooks;
136}
137
138export default books;import AWS from 'aws-sdk';
139import { Author, Authors } from '../../generated/schema';
140
141async function authors(
142 _: unknown,
143 input: { author: Authors }
144): Promise<Author> {
145 const dynamoDb = new AWS.DynamoDB.DocumentClient();
146
147 const params = {
148 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
149 KeyConditionExpression: 'PK = :hkey',
150 ExpressionAttributeValues: {
151 ':hkey': `${input.author}`,
152 },
153 };
154
155 const { Items } = await dynamoDb.query(params).promise();
156
157 console.log({ Items }); // I can see the data but don't know how to returns the data like this below type without using map function
158
159 // type Author {
160 // id: ID!
161 // authorName: String
162 // book: [Book]!
163 // }
164
165 return Items; // return null in Graphql play ground.
166}
167
168export default authors;// resolver map - src/resolvers/index.ts
169const resolvers = {
170 Query: {
171 books,
172 authors,
173 author,
174 book,
175 },
176 Mutation: {
177 createBook,
178 },
179};
180
ANSWER
Answered 2022-Jan-09 at 17:06TL;DR You are missing some resolvers. Your query resolvers are trying to do the job of the missing resolvers. Your resolvers must return data in the right shape.
In other words, your problems are with configuring Apollo Server's resolvers. Nothing Lambda-specific, as far as I can tell.
Write and register the missing resolvers.GraphQL doesn't know how to "resolve" an author's books, for instance. Add a Author {books(parent)}
entry to Apollo Server's resolver map. The corresponding resolver function should return a list of book objects (i.e. [Books]
), as your schema requires. Apollo's docs have a similar example you can adapt.
Here's a refactored author
query, commented with the resolvers that will be called:
1import { gql } from 'apollo-server-lambda';
2
3const typeDefs = gql`
4 enum Genre {
5 adventure
6 drama
7 scifi
8 }
9
10 enum Authors {
11 AUTHOR
12 }
13
14 # Root Query - all the queries supported by the schema
15
16 type Query {
17 """
18 All Authors query
19 """
20 authors(author: Authors): [Author]
21 books(book: String): [Book]
22 }
23
24 # Root Mutation - all the mutations supported by the schema
25 type Mutation {
26 createBook(input: CreateBook!): Book
27 }
28
29 """
30 One Author can have many books
31 """
32 type Author {
33 id: ID!
34 authorName: String
35 book: [Book]!
36 }
37
38 """
39 Book Schema
40 """
41 type Book {
42 id: ID!
43 name: String
44 price: String
45 publishingYear: String
46 publisher: String
47 author: [Author]
48 description: String
49 page: Int
50 genre: [Genre]
51 }
52
53 input CreateBook {
54 name: String
55 price: String
56 publishingYear: String
57 publisher: String
58 author: [CreateAuthor]
59 description: String
60 page: Int
61 genre: [Genre]
62 }
63
64 input CreateAuthor {
65 authorName: String!
66 }
67`;
68export default typeDefs;import AWS from 'aws-sdk';
69import { v4 } from 'uuid';
70import { CreateBook } from '../../generated/schema';
71
72async function createBook(_: unknown, { input }: { input: CreateBook }) {
73 const dynamoDb = new AWS.DynamoDB.DocumentClient();
74 const id = v4();
75
76 const authorsName =
77 input.author &&
78 input.author.map(function (item) {
79 return item['authorName'];
80 });
81
82 const params = {
83 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
84 Item: {
85 PK: `AUTHOR`,
86 SK: `AUTHORS#${id}`,
87 GSI1PK: `BOOKS`,
88 GSI1SK: `BOOK#${input.name}`,
89 name: input.name,
90 author: authorsName,
91 price: input.price,
92 publishingYear: input.publishingYear,
93 publisher: input.publisher,
94 page: input.page,
95 description: input.description,
96 genre: input.genre,
97 },
98 };
99
100 await dynamoDb.put(params).promise();
101
102 return {
103 ...input,
104 id,
105 };
106}
107
108export default createBook;import AWS from 'aws-sdk';
109
110async function books(_: unknown, input: { book: string }) {
111 const dynamoDb = new AWS.DynamoDB.DocumentClient();
112
113 const params = {
114 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
115 IndexName: 'GSI1',
116 KeyConditionExpression: 'GSI1PK = :hkey',
117 ExpressionAttributeValues: {
118 ':hkey': `${input.book}`,
119 },
120 };
121
122 const { Items } = await dynamoDb.query(params).promise();
123
124 const allBooks = // NEED TO MAP THE FUNcTION THEN RETURN THE DATA BASED ON GRAPHQL //QUERIES.
125 Items &&
126 Items.map((i) => {
127 const genre = i.genre.filter((i) => i);
128 return {
129 name: i.name,
130 author: i.author,
131 genre,
132 };
133 });
134
135 return allBooks;
136}
137
138export default books;import AWS from 'aws-sdk';
139import { Author, Authors } from '../../generated/schema';
140
141async function authors(
142 _: unknown,
143 input: { author: Authors }
144): Promise<Author> {
145 const dynamoDb = new AWS.DynamoDB.DocumentClient();
146
147 const params = {
148 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
149 KeyConditionExpression: 'PK = :hkey',
150 ExpressionAttributeValues: {
151 ':hkey': `${input.author}`,
152 },
153 };
154
155 const { Items } = await dynamoDb.query(params).promise();
156
157 console.log({ Items }); // I can see the data but don't know how to returns the data like this below type without using map function
158
159 // type Author {
160 // id: ID!
161 // authorName: String
162 // book: [Book]!
163 // }
164
165 return Items; // return null in Graphql play ground.
166}
167
168export default authors;// resolver map - src/resolvers/index.ts
169const resolvers = {
170 Query: {
171 books,
172 authors,
173 author,
174 book,
175 },
176 Mutation: {
177 createBook,
178 },
179};
180query author(id: '1') { # Query { author } resolver
181 authorName
182 books { # Author { books(parent) } resolver
183 name
184 authors { # Book { author(parent) } resolver
185 id
186 }
187 }
188}
189
Apollo Server uses the resolver map during query execution to decide what resolvers to call for a given query field. It's not a coincidence that the map looks like your schema. Resolver functions are called with parent, arg, context and info arguments, which give your functions the context to fetch the right records from the data source.
1import { gql } from 'apollo-server-lambda';
2
3const typeDefs = gql`
4 enum Genre {
5 adventure
6 drama
7 scifi
8 }
9
10 enum Authors {
11 AUTHOR
12 }
13
14 # Root Query - all the queries supported by the schema
15
16 type Query {
17 """
18 All Authors query
19 """
20 authors(author: Authors): [Author]
21 books(book: String): [Book]
22 }
23
24 # Root Mutation - all the mutations supported by the schema
25 type Mutation {
26 createBook(input: CreateBook!): Book
27 }
28
29 """
30 One Author can have many books
31 """
32 type Author {
33 id: ID!
34 authorName: String
35 book: [Book]!
36 }
37
38 """
39 Book Schema
40 """
41 type Book {
42 id: ID!
43 name: String
44 price: String
45 publishingYear: String
46 publisher: String
47 author: [Author]
48 description: String
49 page: Int
50 genre: [Genre]
51 }
52
53 input CreateBook {
54 name: String
55 price: String
56 publishingYear: String
57 publisher: String
58 author: [CreateAuthor]
59 description: String
60 page: Int
61 genre: [Genre]
62 }
63
64 input CreateAuthor {
65 authorName: String!
66 }
67`;
68export default typeDefs;import AWS from 'aws-sdk';
69import { v4 } from 'uuid';
70import { CreateBook } from '../../generated/schema';
71
72async function createBook(_: unknown, { input }: { input: CreateBook }) {
73 const dynamoDb = new AWS.DynamoDB.DocumentClient();
74 const id = v4();
75
76 const authorsName =
77 input.author &&
78 input.author.map(function (item) {
79 return item['authorName'];
80 });
81
82 const params = {
83 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
84 Item: {
85 PK: `AUTHOR`,
86 SK: `AUTHORS#${id}`,
87 GSI1PK: `BOOKS`,
88 GSI1SK: `BOOK#${input.name}`,
89 name: input.name,
90 author: authorsName,
91 price: input.price,
92 publishingYear: input.publishingYear,
93 publisher: input.publisher,
94 page: input.page,
95 description: input.description,
96 genre: input.genre,
97 },
98 };
99
100 await dynamoDb.put(params).promise();
101
102 return {
103 ...input,
104 id,
105 };
106}
107
108export default createBook;import AWS from 'aws-sdk';
109
110async function books(_: unknown, input: { book: string }) {
111 const dynamoDb = new AWS.DynamoDB.DocumentClient();
112
113 const params = {
114 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
115 IndexName: 'GSI1',
116 KeyConditionExpression: 'GSI1PK = :hkey',
117 ExpressionAttributeValues: {
118 ':hkey': `${input.book}`,
119 },
120 };
121
122 const { Items } = await dynamoDb.query(params).promise();
123
124 const allBooks = // NEED TO MAP THE FUNcTION THEN RETURN THE DATA BASED ON GRAPHQL //QUERIES.
125 Items &&
126 Items.map((i) => {
127 const genre = i.genre.filter((i) => i);
128 return {
129 name: i.name,
130 author: i.author,
131 genre,
132 };
133 });
134
135 return allBooks;
136}
137
138export default books;import AWS from 'aws-sdk';
139import { Author, Authors } from '../../generated/schema';
140
141async function authors(
142 _: unknown,
143 input: { author: Authors }
144): Promise<Author> {
145 const dynamoDb = new AWS.DynamoDB.DocumentClient();
146
147 const params = {
148 TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
149 KeyConditionExpression: 'PK = :hkey',
150 ExpressionAttributeValues: {
151 ':hkey': `${input.author}`,
152 },
153 };
154
155 const { Items } = await dynamoDb.query(params).promise();
156
157 console.log({ Items }); // I can see the data but don't know how to returns the data like this below type without using map function
158
159 // type Author {
160 // id: ID!
161 // authorName: String
162 // book: [Book]!
163 // }
164
165 return Items; // return null in Graphql play ground.
166}
167
168export default authors;// resolver map - src/resolvers/index.ts
169const resolvers = {
170 Query: {
171 books,
172 authors,
173 author,
174 book,
175 },
176 Mutation: {
177 createBook,
178 },
179};
180query author(id: '1') { # Query { author } resolver
181 authorName
182 books { # Author { books(parent) } resolver
183 name
184 authors { # Book { author(parent) } resolver
185 id
186 }
187 }
188}
189// resolver map - passed to the Apollo Server constructor
190const resolvers = {
191 Query: {
192 books,
193 authors,
194 author,
195 book,
196 },
197
198 Author: {
199 books(parent) { getAuthorBooks(parent); }, // parent is the author - resolver should return a list of books
200 },
201
202 Book: {
203 authors(parent) { getBookAuthors(parent); }, // parent is the book - resolver should return a list of authors
204 },
205};
206
It's not the author query resolver's job to resolve all the child fields. Apollo Server will call multiple resolvers multiple times during query execution:
You can think of each field in a GraphQL query as a function or method of the previous type which returns the next type. In fact, this is exactly how GraphQL works. Each field on each type is backed by a function called the resolver which is provided by the GraphQL server developer. When a field is executed, the corresponding resolver is called to produce the next value
Apollo Server calls this the resolver chain. The books(parent)
resolver will be invoked with Author
as its parent
argument. You can use the author id to look up her books.
Make sure your resolvers are returning data in the shape required by the schema. Your author
resolver is apparently returning a map {Items: [author-record]}
, but your schema says it needs to be a list.
(If I were you, I would change the author query signature from author(PK: String, SK: String): [Author]
to something more caller-friendly like author(id: ID): Author
. Return an Object, not a List. Hide the DynamoDB implementation details in the resolver function. Apollo Server has a ID
scalar type that is serialised as a String.)
QUESTION
How to use Graphql typescript types in react
Asked 2022-Jan-06 at 20:58I have a react app with a keystone.js backend and a graphql api
I have a list of products in keystones.js and a simple graphql query
1import gql from "graphql-tag";
2
3export const ALL_PRODUCTS_QUERY = gql`
4 query ProductData{
5 allProducts{
6 id
7 price
8 description
9 name
10 }
11 }
12`
13
I'm using apollo codegen to generate the types for the graphql so I get
1import gql from "graphql-tag";
2
3export const ALL_PRODUCTS_QUERY = gql`
4 query ProductData{
5 allProducts{
6 id
7 price
8 description
9 name
10 }
11 }
12`
13export interface ProductData_allProducts {
14 __typename: "Product";
15 id: string;
16 price: number | null;
17 description: string | null;
18 name: string | null;
19}
20
21export interface ProductData {
22 /**
23 * Search for all Product items which match the where clause.
24 */
25 allProducts: (ProductData_allProducts | null)[] | null;
26}
27
In React I can list the products and use the types in the code, here I'm using <ProductData>
1import gql from "graphql-tag";
2
3export const ALL_PRODUCTS_QUERY = gql`
4 query ProductData{
5 allProducts{
6 id
7 price
8 description
9 name
10 }
11 }
12`
13export interface ProductData_allProducts {
14 __typename: "Product";
15 id: string;
16 price: number | null;
17 description: string | null;
18 name: string | null;
19}
20
21export interface ProductData {
22 /**
23 * Search for all Product items which match the where clause.
24 */
25 allProducts: (ProductData_allProducts | null)[] | null;
26}
27import { useQuery } from "@apollo/client";
28import {ALL_PRODUCTS_QUERY} from '../queries/index'
29import { ProductData } from "../generated/ProductData";
30
31const Products = () => {
32
33 const {data, error, loading} = useQuery<ProductData>(ALL_PRODUCTS_QUERY)
34 if(loading) return <p>Loading</p>
35 if(error) return <p>Error: {error.message}</p>
36
37 return (
38 <div>
39 <div>
40 {data?.allProducts?.map(product => (
41 <div>{product?.name}</div>
42 ))}
43 </div>
44 </div>
45 );
46};
47
48export default Products;
49
Instead of using <div>{product?.name}</div>
I would like to create a Product
component
1import gql from "graphql-tag";
2
3export const ALL_PRODUCTS_QUERY = gql`
4 query ProductData{
5 allProducts{
6 id
7 price
8 description
9 name
10 }
11 }
12`
13export interface ProductData_allProducts {
14 __typename: "Product";
15 id: string;
16 price: number | null;
17 description: string | null;
18 name: string | null;
19}
20
21export interface ProductData {
22 /**
23 * Search for all Product items which match the where clause.
24 */
25 allProducts: (ProductData_allProducts | null)[] | null;
26}
27import { useQuery } from "@apollo/client";
28import {ALL_PRODUCTS_QUERY} from '../queries/index'
29import { ProductData } from "../generated/ProductData";
30
31const Products = () => {
32
33 const {data, error, loading} = useQuery<ProductData>(ALL_PRODUCTS_QUERY)
34 if(loading) return <p>Loading</p>
35 if(error) return <p>Error: {error.message}</p>
36
37 return (
38 <div>
39 <div>
40 {data?.allProducts?.map(product => (
41 <div>{product?.name}</div>
42 ))}
43 </div>
44 </div>
45 );
46};
47
48export default Products;
49import React from 'react';
50import { ProductData, ProductData_allProducts } from '../generated/ProductData';
51
52const Product = ({product}:ProductData_allProducts) => {
53 return (
54 <p>{product.name}</p>
55 );
56};
57
58export default Product;
59
but what should the type be for product
here I get an error saying
1import gql from "graphql-tag";
2
3export const ALL_PRODUCTS_QUERY = gql`
4 query ProductData{
5 allProducts{
6 id
7 price
8 description
9 name
10 }
11 }
12`
13export interface ProductData_allProducts {
14 __typename: "Product";
15 id: string;
16 price: number | null;
17 description: string | null;
18 name: string | null;
19}
20
21export interface ProductData {
22 /**
23 * Search for all Product items which match the where clause.
24 */
25 allProducts: (ProductData_allProducts | null)[] | null;
26}
27import { useQuery } from "@apollo/client";
28import {ALL_PRODUCTS_QUERY} from '../queries/index'
29import { ProductData } from "../generated/ProductData";
30
31const Products = () => {
32
33 const {data, error, loading} = useQuery<ProductData>(ALL_PRODUCTS_QUERY)
34 if(loading) return <p>Loading</p>
35 if(error) return <p>Error: {error.message}</p>
36
37 return (
38 <div>
39 <div>
40 {data?.allProducts?.map(product => (
41 <div>{product?.name}</div>
42 ))}
43 </div>
44 </div>
45 );
46};
47
48export default Products;
49import React from 'react';
50import { ProductData, ProductData_allProducts } from '../generated/ProductData';
51
52const Product = ({product}:ProductData_allProducts) => {
53 return (
54 <p>{product.name}</p>
55 );
56};
57
58export default Product;
59Property 'product' does not exist on type 'ProductData_allProducts'.
60
and on the Products page
1import gql from "graphql-tag";
2
3export const ALL_PRODUCTS_QUERY = gql`
4 query ProductData{
5 allProducts{
6 id
7 price
8 description
9 name
10 }
11 }
12`
13export interface ProductData_allProducts {
14 __typename: "Product";
15 id: string;
16 price: number | null;
17 description: string | null;
18 name: string | null;
19}
20
21export interface ProductData {
22 /**
23 * Search for all Product items which match the where clause.
24 */
25 allProducts: (ProductData_allProducts | null)[] | null;
26}
27import { useQuery } from "@apollo/client";
28import {ALL_PRODUCTS_QUERY} from '../queries/index'
29import { ProductData } from "../generated/ProductData";
30
31const Products = () => {
32
33 const {data, error, loading} = useQuery<ProductData>(ALL_PRODUCTS_QUERY)
34 if(loading) return <p>Loading</p>
35 if(error) return <p>Error: {error.message}</p>
36
37 return (
38 <div>
39 <div>
40 {data?.allProducts?.map(product => (
41 <div>{product?.name}</div>
42 ))}
43 </div>
44 </div>
45 );
46};
47
48export default Products;
49import React from 'react';
50import { ProductData, ProductData_allProducts } from '../generated/ProductData';
51
52const Product = ({product}:ProductData_allProducts) => {
53 return (
54 <p>{product.name}</p>
55 );
56};
57
58export default Product;
59Property 'product' does not exist on type 'ProductData_allProducts'.
60import { useQuery } from "@apollo/client";
61import {ALL_PRODUCTS_QUERY} from '../queries/index'
62import { ProductData } from "../generated/ProductData";
63import Product from "./Product";
64
65
66const Products = () => {
67
68 const {data, error, loading} = useQuery<ProductData>(ALL_PRODUCTS_QUERY)
69 if(loading) return <p>Loading</p>
70 if(error) return <p>Error: {error.message}</p>
71
72 return (
73 <div>
74 <div>
75 {data?.allProducts?.map(product => (
76 <Product product={product} />
77 ))}
78 </div>
79 </div>
80 );
81};
82
83export default Products;
84
I now get an error on the product prop
1import gql from "graphql-tag";
2
3export const ALL_PRODUCTS_QUERY = gql`
4 query ProductData{
5 allProducts{
6 id
7 price
8 description
9 name
10 }
11 }
12`
13export interface ProductData_allProducts {
14 __typename: "Product";
15 id: string;
16 price: number | null;
17 description: string | null;
18 name: string | null;
19}
20
21export interface ProductData {
22 /**
23 * Search for all Product items which match the where clause.
24 */
25 allProducts: (ProductData_allProducts | null)[] | null;
26}
27import { useQuery } from "@apollo/client";
28import {ALL_PRODUCTS_QUERY} from '../queries/index'
29import { ProductData } from "../generated/ProductData";
30
31const Products = () => {
32
33 const {data, error, loading} = useQuery<ProductData>(ALL_PRODUCTS_QUERY)
34 if(loading) return <p>Loading</p>
35 if(error) return <p>Error: {error.message}</p>
36
37 return (
38 <div>
39 <div>
40 {data?.allProducts?.map(product => (
41 <div>{product?.name}</div>
42 ))}
43 </div>
44 </div>
45 );
46};
47
48export default Products;
49import React from 'react';
50import { ProductData, ProductData_allProducts } from '../generated/ProductData';
51
52const Product = ({product}:ProductData_allProducts) => {
53 return (
54 <p>{product.name}</p>
55 );
56};
57
58export default Product;
59Property 'product' does not exist on type 'ProductData_allProducts'.
60import { useQuery } from "@apollo/client";
61import {ALL_PRODUCTS_QUERY} from '../queries/index'
62import { ProductData } from "../generated/ProductData";
63import Product from "./Product";
64
65
66const Products = () => {
67
68 const {data, error, loading} = useQuery<ProductData>(ALL_PRODUCTS_QUERY)
69 if(loading) return <p>Loading</p>
70 if(error) return <p>Error: {error.message}</p>
71
72 return (
73 <div>
74 <div>
75 {data?.allProducts?.map(product => (
76 <Product product={product} />
77 ))}
78 </div>
79 </div>
80 );
81};
82
83export default Products;
84Type '{ product: ProductData_allProducts | null; }' is not assignable to type 'IntrinsicAttributes & ProductData_allProducts'.
85 Property 'product' does not exist on type 'IntrinsicAttributes & ProductData_allProducts'.
86
So what should the types be on the Product page when passing in the product
ANSWER
Answered 2021-Dec-30 at 08:46You are trying to destructure a property that doesnt exist on the type.
This should work:
1import gql from "graphql-tag";
2
3export const ALL_PRODUCTS_QUERY = gql`
4 query ProductData{
5 allProducts{
6 id
7 price
8 description
9 name
10 }
11 }
12`
13export interface ProductData_allProducts {
14 __typename: "Product";
15 id: string;
16 price: number | null;
17 description: string | null;
18 name: string | null;
19}
20
21export interface ProductData {
22 /**
23 * Search for all Product items which match the where clause.
24 */
25 allProducts: (ProductData_allProducts | null)[] | null;
26}
27import { useQuery } from "@apollo/client";
28import {ALL_PRODUCTS_QUERY} from '../queries/index'
29import { ProductData } from "../generated/ProductData";
30
31const Products = () => {
32
33 const {data, error, loading} = useQuery<ProductData>(ALL_PRODUCTS_QUERY)
34 if(loading) return <p>Loading</p>
35 if(error) return <p>Error: {error.message}</p>
36
37 return (
38 <div>
39 <div>
40 {data?.allProducts?.map(product => (
41 <div>{product?.name}</div>
42 ))}
43 </div>
44 </div>
45 );
46};
47
48export default Products;
49import React from 'react';
50import { ProductData, ProductData_allProducts } from '../generated/ProductData';
51
52const Product = ({product}:ProductData_allProducts) => {
53 return (
54 <p>{product.name}</p>
55 );
56};
57
58export default Product;
59Property 'product' does not exist on type 'ProductData_allProducts'.
60import { useQuery } from "@apollo/client";
61import {ALL_PRODUCTS_QUERY} from '../queries/index'
62import { ProductData } from "../generated/ProductData";
63import Product from "./Product";
64
65
66const Products = () => {
67
68 const {data, error, loading} = useQuery<ProductData>(ALL_PRODUCTS_QUERY)
69 if(loading) return <p>Loading</p>
70 if(error) return <p>Error: {error.message}</p>
71
72 return (
73 <div>
74 <div>
75 {data?.allProducts?.map(product => (
76 <Product product={product} />
77 ))}
78 </div>
79 </div>
80 );
81};
82
83export default Products;
84Type '{ product: ProductData_allProducts | null; }' is not assignable to type 'IntrinsicAttributes & ProductData_allProducts'.
85 Property 'product' does not exist on type 'IntrinsicAttributes & ProductData_allProducts'.
86type Product = {
87 __typename: "Product";
88 id: string;
89 price: number | null;
90 description: string | null;
91 name: string | null;
92};
93
94const ProductComponent: FC<Product> = ({ name }) => {
95 return <p>{name}</p>;
96};
97
98export default ProductComponent;
99
QUESTION
Testing React Component with React Router V6
Asked 2022-Jan-02 at 08:29I understand that React Testing Library has an example of testing with react router, but I couldn't get it to work (I think because I am using react router V6).
Basically, I need router testing because I have details component that uses useParams() to get part of the url. I can't render the component without it.
This was my attempt to make it work (yes the page also needs apollo, although it doesn't really need redux).
1const AllTheProviders = ({children, initialRoutes}) => {
2 return (
3 <ApolloProvider client={client}>
4 <Provider store={store}>
5 <MemoryRouter>
6 {children}
7 </MemoryRouter>
8 </Provider>
9 </ApolloProvider>
10 );
11}
12const customRender = (ui, options) => render(ui, {wrapper: AllTheProviders, ...options})
13
14
15beforeEach(() => {
16 window.history.pushState({}, 'Test page',"/details/url-param-the-component-needs")
17 customRender(<App/>);
18});
19
No surprise, but this didn't work. I assume window.history.pushState() doesn't work for react router V6. I tried using useNavigate(), but that doesn't work outside of a component.
If anybody has any ideas on how I could make this work. I would greatly appreciate it.
ANSWER
Answered 2022-Jan-02 at 08:291const AllTheProviders = ({children, initialRoutes}) => {
2 return (
3 <ApolloProvider client={client}>
4 <Provider store={store}>
5 <MemoryRouter>
6 {children}
7 </MemoryRouter>
8 </Provider>
9 </ApolloProvider>
10 );
11}
12const customRender = (ui, options) => render(ui, {wrapper: AllTheProviders, ...options})
13
14
15beforeEach(() => {
16 window.history.pushState({}, 'Test page',"/details/url-param-the-component-needs")
17 customRender(<App/>);
18});
19declare function MemoryRouter(
20 props: MemoryRouterProps
21): React.ReactElement;
22
23interface MemoryRouterProps {
24 basename?: string;
25 children?: React.ReactNode;
26 initialEntries?: InitialEntry[];
27 initialIndex?: number;
28}
29
I would remove the MemoryRouter
from the customRender
and just wrap the component under test locally and pass in the specific initial route entries for the test.
1const AllTheProviders = ({children, initialRoutes}) => {
2 return (
3 <ApolloProvider client={client}>
4 <Provider store={store}>
5 <MemoryRouter>
6 {children}
7 </MemoryRouter>
8 </Provider>
9 </ApolloProvider>
10 );
11}
12const customRender = (ui, options) => render(ui, {wrapper: AllTheProviders, ...options})
13
14
15beforeEach(() => {
16 window.history.pushState({}, 'Test page',"/details/url-param-the-component-needs")
17 customRender(<App/>);
18});
19declare function MemoryRouter(
20 props: MemoryRouterProps
21): React.ReactElement;
22
23interface MemoryRouterProps {
24 basename?: string;
25 children?: React.ReactNode;
26 initialEntries?: InitialEntry[];
27 initialIndex?: number;
28}
29const AllTheProviders = ({ children }) => {
30 return (
31 <ApolloProvider client={client}>
32 <Provider store={store}>
33 {children}
34 </Provider>
35 </ApolloProvider>
36 );
37};
38const customRender = (ui, options) =>
39 render(ui, { wrapper: AllTheProviders, ...options });
40
...
1const AllTheProviders = ({children, initialRoutes}) => {
2 return (
3 <ApolloProvider client={client}>
4 <Provider store={store}>
5 <MemoryRouter>
6 {children}
7 </MemoryRouter>
8 </Provider>
9 </ApolloProvider>
10 );
11}
12const customRender = (ui, options) => render(ui, {wrapper: AllTheProviders, ...options})
13
14
15beforeEach(() => {
16 window.history.pushState({}, 'Test page',"/details/url-param-the-component-needs")
17 customRender(<App/>);
18});
19declare function MemoryRouter(
20 props: MemoryRouterProps
21): React.ReactElement;
22
23interface MemoryRouterProps {
24 basename?: string;
25 children?: React.ReactNode;
26 initialEntries?: InitialEntry[];
27 initialIndex?: number;
28}
29const AllTheProviders = ({ children }) => {
30 return (
31 <ApolloProvider client={client}>
32 <Provider store={store}>
33 {children}
34 </Provider>
35 </ApolloProvider>
36 );
37};
38const customRender = (ui, options) =>
39 render(ui, { wrapper: AllTheProviders, ...options });
40const { ....queries.... } = customRender(
41 <MemoryRouter
42 initialEntries={["Test page", "/details/url-param-the-component-needs"]}
43 >
44 <ComponentUnderTest />
45 </MemoryRouter>
46);
47
An additional thought, the useParams
hook may also need a Route
with a path
prop specifying the match params the component needs, so your test could potentially look like the following:
1const AllTheProviders = ({children, initialRoutes}) => {
2 return (
3 <ApolloProvider client={client}>
4 <Provider store={store}>
5 <MemoryRouter>
6 {children}
7 </MemoryRouter>
8 </Provider>
9 </ApolloProvider>
10 );
11}
12const customRender = (ui, options) => render(ui, {wrapper: AllTheProviders, ...options})
13
14
15beforeEach(() => {
16 window.history.pushState({}, 'Test page',"/details/url-param-the-component-needs")
17 customRender(<App/>);
18});
19declare function MemoryRouter(
20 props: MemoryRouterProps
21): React.ReactElement;
22
23interface MemoryRouterProps {
24 basename?: string;
25 children?: React.ReactNode;
26 initialEntries?: InitialEntry[];
27 initialIndex?: number;
28}
29const AllTheProviders = ({ children }) => {
30 return (
31 <ApolloProvider client={client}>
32 <Provider store={store}>
33 {children}
34 </Provider>
35 </ApolloProvider>
36 );
37};
38const customRender = (ui, options) =>
39 render(ui, { wrapper: AllTheProviders, ...options });
40const { ....queries.... } = customRender(
41 <MemoryRouter
42 initialEntries={["Test page", "/details/url-param-the-component-needs"]}
43 >
44 <ComponentUnderTest />
45 </MemoryRouter>
46);
47const { ....queries.... } = customRender(
48 <MemoryRouter
49 initialEntries={["Test page", "/details/url-param-the-component-needs"]}
50 >
51 <Routes>
52 <Route path="/details/:theParam" element={<ComponentUnderTest />} />
53 </Routes>
54 </MemoryRouter>
55);
56
QUESTION
Error: GraphQL error: Field 'metafieldsSet' doesn't exist on type 'Mutation' - Shopify GraphQL error
Asked 2021-Dec-08 at 14:21I have been recently playing with Shopify App Development and i'm struggling with a graphql call to amend some text. The image below displays the call being made correctly in the shopify GraphQL app which is where I test it.
However when I attempt to make this same call from the react component I get the following error
1Unhandled Runtime Error
2Error: GraphQL error: Field 'metafieldsSet' doesn't exist on type 'Mutation'
3GraphQL error: Variable $metafields is declared by metafieldsSet but not used
4
Here is the react component in which I try and update the metafield
1Unhandled Runtime Error
2Error: GraphQL error: Field 'metafieldsSet' doesn't exist on type 'Mutation'
3GraphQL error: Variable $metafields is declared by metafieldsSet but not used
4import React, { useState } from 'react';
5import gql from 'graphql-tag';
6import { Mutation } from 'react-apollo';
7import { Layout, Button, Banner, Toast, Stack, Frame } from '@shopify/polaris';
8import { Context } from '@shopify/app-bridge-react';
9// GraphQL mutation that updates the prices of products
10const UPDATE_TEXT = gql`mutation metafieldsSet($metafields: [MetafieldsSetInput!]!) {
11 metafieldsSet(metafields: $metafields) {
12 metafields {
13 value
14 id
15 key
16 ownerType
17
18 }
19 userErrors {
20 field
21 message
22 }
23 }
24 }
25`;
26class UpdateTheText extends React.Component{
27 static contextType = Context;
28 render(){
29 return(
30 <Mutation mutation={UPDATE_TEXT}>
31 {(handleSubmit, {error, data}) => {
32 const [hasResults, setHasResults] = useState(false);
33
34 const showError = error && (
35 <Banner status="critical">{error.message}</Banner>
36 );
37
38 const showToast = hasResults && (
39 <Toast
40 content="Successfully updated"
41 onDismiss={() => setHasResults(false)}
42 />
43 );
44
45 return (
46 <Frame>
47 {showToast}
48 <Layout.Section>
49 {showError}
50 </Layout.Section>
51
52 <Layout.Section>
53 <Stack distribution={"center"}>
54 <Button
55 primary
56 textAlign={"center"}
57 onClick={() => {
58 let promise = new Promise((resolve) => resolve());
59 const newmetafields = {
60 key: "ExtraShopDesc",
61 namespace: "ExtraShopDescription",
62 ownerId: "gid://shopify/Shop/55595073672",
63 type: "single_line_text_field",
64 value: "This is an extra shop description twice"
65 }
66
67 promise = promise.then(() => handleSubmit({ variables: { metafields: newmetafields }}));
68
69
70 if (promise) {
71 promise.then(() => this.props.onUpdate().then(() => setHasResults(true)));
72 }}
73 }
74 >
75 Update Text
76 </Button>
77 </Stack>
78 </Layout.Section>
79 </Frame>
80 );
81 }}
82 </Mutation>
83 );
84 }
85
86}
87
88export default UpdateTheText;
89
I believe i'm passing the variables into the gql but it doesn't seem to be picking them up?
ANSWER
Answered 2021-Dec-08 at 14:21Sigh,
This all along was an API version issue. Shopify CLI still spins up Oct 2020 API. Metafieldset was only added in the 2021 API
https://shopify.dev/api/admin-graphql/2021-10/mutations/metafieldsset
The error messages threw me off
So to update just update the API version in server.js
1Unhandled Runtime Error
2Error: GraphQL error: Field 'metafieldsSet' doesn't exist on type 'Mutation'
3GraphQL error: Variable $metafields is declared by metafieldsSet but not used
4import React, { useState } from 'react';
5import gql from 'graphql-tag';
6import { Mutation } from 'react-apollo';
7import { Layout, Button, Banner, Toast, Stack, Frame } from '@shopify/polaris';
8import { Context } from '@shopify/app-bridge-react';
9// GraphQL mutation that updates the prices of products
10const UPDATE_TEXT = gql`mutation metafieldsSet($metafields: [MetafieldsSetInput!]!) {
11 metafieldsSet(metafields: $metafields) {
12 metafields {
13 value
14 id
15 key
16 ownerType
17
18 }
19 userErrors {
20 field
21 message
22 }
23 }
24 }
25`;
26class UpdateTheText extends React.Component{
27 static contextType = Context;
28 render(){
29 return(
30 <Mutation mutation={UPDATE_TEXT}>
31 {(handleSubmit, {error, data}) => {
32 const [hasResults, setHasResults] = useState(false);
33
34 const showError = error && (
35 <Banner status="critical">{error.message}</Banner>
36 );
37
38 const showToast = hasResults && (
39 <Toast
40 content="Successfully updated"
41 onDismiss={() => setHasResults(false)}
42 />
43 );
44
45 return (
46 <Frame>
47 {showToast}
48 <Layout.Section>
49 {showError}
50 </Layout.Section>
51
52 <Layout.Section>
53 <Stack distribution={"center"}>
54 <Button
55 primary
56 textAlign={"center"}
57 onClick={() => {
58 let promise = new Promise((resolve) => resolve());
59 const newmetafields = {
60 key: "ExtraShopDesc",
61 namespace: "ExtraShopDescription",
62 ownerId: "gid://shopify/Shop/55595073672",
63 type: "single_line_text_field",
64 value: "This is an extra shop description twice"
65 }
66
67 promise = promise.then(() => handleSubmit({ variables: { metafields: newmetafields }}));
68
69
70 if (promise) {
71 promise.then(() => this.props.onUpdate().then(() => setHasResults(true)));
72 }}
73 }
74 >
75 Update Text
76 </Button>
77 </Stack>
78 </Layout.Section>
79 </Frame>
80 );
81 }}
82 </Mutation>
83 );
84 }
85
86}
87
88export default UpdateTheText;
89API_VERSION: "2021-10",
90
QUESTION
Error: You must `await server.start()` before calling `server.applyMiddleware()`
Asked 2021-Nov-30 at 06:45After updating the apollo-server
to version 3 the following error is shown in the console
1C:\projects\my_project\node_modules\apollo-server-core\src\ApolloServer.ts:554
2 throw new Error(
3 ^
4Error: You must `await server.start()` before calling `server.applyMiddleware()`
5 at ApolloServer.assertStarted (C:\projects\my_project\node_modules\apollo-server-core\src\ApolloServer.ts:554:13)
6 at ApolloServer.applyMiddleware (C:\projects\my_project\node_modules\apollo-server-express\src\ApolloServer.ts:60:10)
7 at Object.<anonymous> (C:\projects\my_project\src\index.ts:17:14)
8 at Module._compile (internal/modules/cjs/loader.js:1063:30)
9 at Module.m._compile (C:\projects\my_project\node_modules\ts-node\src\index.ts:1225:23)
10 at Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
11 at Object.require.extensions.<computed> [as .ts] (C:\projects\my_project\node_modules\ts-node\src\index.ts:1228:12)
12 at Module.load (internal/modules/cjs/loader.js:928:32)
13 at Function.Module._load (internal/modules/cjs/loader.js:769:14)
14 at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
15[nodemon] app crashed - waiting for file changes before starting...
16
Adding server.start()
before server.applyMiddleware()
doesn't fix the problem. Any suggestions?
ANSWER
Answered 2021-Aug-01 at 21:48I was able to fix the issue by following this guide in the documentation.
This example is copy-pasted from the documentation
1C:\projects\my_project\node_modules\apollo-server-core\src\ApolloServer.ts:554
2 throw new Error(
3 ^
4Error: You must `await server.start()` before calling `server.applyMiddleware()`
5 at ApolloServer.assertStarted (C:\projects\my_project\node_modules\apollo-server-core\src\ApolloServer.ts:554:13)
6 at ApolloServer.applyMiddleware (C:\projects\my_project\node_modules\apollo-server-express\src\ApolloServer.ts:60:10)
7 at Object.<anonymous> (C:\projects\my_project\src\index.ts:17:14)
8 at Module._compile (internal/modules/cjs/loader.js:1063:30)
9 at Module.m._compile (C:\projects\my_project\node_modules\ts-node\src\index.ts:1225:23)
10 at Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
11 at Object.require.extensions.<computed> [as .ts] (C:\projects\my_project\node_modules\ts-node\src\index.ts:1228:12)
12 at Module.load (internal/modules/cjs/loader.js:928:32)
13 at Function.Module._load (internal/modules/cjs/loader.js:769:14)
14 at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
15[nodemon] app crashed - waiting for file changes before starting...
16import { ApolloServer } from 'apollo-server-express';
17import express from 'express';
18
19async function startApolloServer(typeDefs, resolvers) {
20 // Same ApolloServer initialization as before
21 const server = new ApolloServer({ typeDefs, resolvers });
22
23 // Required logic for integrating with Express
24 await server.start();
25
26 const app = express();
27
28 server.applyMiddleware({
29 app,
30
31 // By default, apollo-server hosts its GraphQL endpoint at the
32 // server root. However, *other* Apollo Server packages host it at
33 // /graphql. Optionally provide this to match apollo-server.
34 path: '/'
35 });
36
37 // Modified server startup
38 await new Promise(resolve => app.listen({ port: 4000 }, resolve));
39 console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`);
40}
41
Community Discussions contain sources that include Stack Exchange Network
Tutorials and Learning Resources in Apollo
Tutorials and Learning Resources are not available at this moment for Apollo