AWS Graphql lambda 查询
AWS Graphql lambda query
我没有为此应用程序使用 AWS AppSync。我已经创建了 Graphql 架构,我已经制作了自己的解析器。对于每个创建、查询,我都制作了每个 Lambda 函数。我使用了 DynamoDB Single table 概念,它是全局二级索引。
创建图书项目对我来说没问题。在 DynamoDB 中,table 看起来像这样:.
我对 return Graphql 查询有疑问。从 DynamoDB table 获取 Items
后,我必须使用 Map 函数,然后 return 基于 Graphql type
的 Items
。我觉得这不是有效的方法。 Idk 查询数据的最佳方式。此外,作者和作者查询都为空。
这是我的gitlab-branch。
这是我的 Graphql 模式
import { gql } from 'apollo-server-lambda';
const typeDefs = gql`
enum Genre {
adventure
drama
scifi
}
enum Authors {
AUTHOR
}
# Root Query - all the queries supported by the schema
type Query {
"""
All Authors query
"""
authors(author: Authors): [Author]
books(book: String): [Book]
}
# Root Mutation - all the mutations supported by the schema
type Mutation {
createBook(input: CreateBook!): Book
}
"""
One Author can have many books
"""
type Author {
id: ID!
authorName: String
book: [Book]!
}
"""
Book Schema
"""
type Book {
id: ID!
name: String
price: String
publishingYear: String
publisher: String
author: [Author]
description: String
page: Int
genre: [Genre]
}
input CreateBook {
name: String
price: String
publishingYear: String
publisher: String
author: [CreateAuthor]
description: String
page: Int
genre: [Genre]
}
input CreateAuthor {
authorName: String!
}
`;
export default typeDefs;
这是我创建的图书项目
import AWS from 'aws-sdk';
import { v4 } from 'uuid';
import { CreateBook } from '../../generated/schema';
async function createBook(_: unknown, { input }: { input: CreateBook }) {
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const id = v4();
const authorsName =
input.author &&
input.author.map(function (item) {
return item['authorName'];
});
const params = {
TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
Item: {
PK: `AUTHOR`,
SK: `AUTHORS#${id}`,
GSI1PK: `BOOKS`,
GSI1SK: `BOOK#${input.name}`,
name: input.name,
author: authorsName,
price: input.price,
publishingYear: input.publishingYear,
publisher: input.publisher,
page: input.page,
description: input.description,
genre: input.genre,
},
};
await dynamoDb.put(params).promise();
return {
...input,
id,
};
}
export default createBook;
这是查询全书的方法
import AWS from 'aws-sdk';
async function books(_: unknown, input: { book: string }) {
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const params = {
TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
IndexName: 'GSI1',
KeyConditionExpression: 'GSI1PK = :hkey',
ExpressionAttributeValues: {
':hkey': `${input.book}`,
},
};
const { Items } = await dynamoDb.query(params).promise();
const allBooks = // NEED TO MAP THE FUNcTION THEN RETURN THE DATA BASED ON GRAPHQL //QUERIES.
Items &&
Items.map((i) => {
const genre = i.genre.filter((i) => i);
return {
name: i.name,
author: i.author,
genre,
};
});
return allBooks;
}
export default books;
这是我的作者查询和控制台结果的图像
import AWS from 'aws-sdk';
import { Author, Authors } from '../../generated/schema';
async function authors(
_: unknown,
input: { author: Authors }
): Promise<Author> {
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const params = {
TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
KeyConditionExpression: 'PK = :hkey',
ExpressionAttributeValues: {
':hkey': `${input.author}`,
},
};
const { Items } = await dynamoDb.query(params).promise();
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
// type Author {
// id: ID!
// authorName: String
// book: [Book]!
// }
return Items; // return null in Graphql play ground.
}
export default authors;
编辑:当前解析器映射
// resolver map - src/resolvers/index.ts
const resolvers = {
Query: {
books,
authors,
author,
book,
},
Mutation: {
createBook,
},
};
TL;DR 您缺少一些解析器。您的查询解析器正在尝试完成缺少的解析器的工作。您的解析器必须 return 数据格式正确。
换句话说,您的问题出在配置 Apollo Server 的解析器上。据我所知,没有什么是特定于 Lambda 的。
编写并注册缺少的解析器。
例如,GraphQL 不知道如何“解析”作者的书籍。添加一个 Author {books(parent)}
条目到 Apollo Server 的 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 你可以适应。
这是一个重构的 author
查询,注释了将调用的解析器:
query author(id: '1') { # Query { author } resolver
authorName
books { # Author { books(parent) } resolver
name
authors { # Book { author(parent) } resolver
id
}
}
}
Apollo 服务器在查询执行期间使用解析器映射来决定为给定查询字段调用哪些解析器。地图看起来像您的模式并非巧合。使用 parent, arg, context and info 个参数调用解析器函数,这为您的函数提供了从数据源获取正确记录的上下文。
// resolver map - passed to the Apollo Server constructor
const resolvers = {
Query: {
books,
authors,
author,
book,
},
Author: {
books(parent) { getAuthorBooks(parent); }, // parent is the author - resolver should return a list of books
},
Book: {
authors(parent) { getBookAuthors(parent); }, // parent is the book - resolver should return a list of authors
},
};
您的查询解析器试图做太多的工作。
解析所有子字段不是作者查询解析器的工作。 Apollo Server 会多次调用多个解析器 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 服务器称其为 resolver chain。 books(parent)
解析器将以 Author
作为其 parent
参数被调用。可以用作者id查她的书
您的解析器 return 值必须与架构一致。
确保您的解析器return正在按照架构所需的形式处理数据。您的 author
解析器显然正在 return 映射 {Items: [author-record]}
,但您的模式说它需要是一个列表。
(如果我是你,我会将作者查询签名从 author(PK: String, SK: String): [Author]
更改为对调用者更友好的内容,例如 author(id: ID): Author
。Return 一个对象,而不是一个列表。隐藏解析器函数中的 DynamoDB 实现细节。Apollo Server 有一个 ID
标量类型,即 serialised as a String。)
我没有为此应用程序使用 AWS AppSync。我已经创建了 Graphql 架构,我已经制作了自己的解析器。对于每个创建、查询,我都制作了每个 Lambda 函数。我使用了 DynamoDB Single table 概念,它是全局二级索引。
创建图书项目对我来说没问题。在 DynamoDB 中,table 看起来像这样:
我对 return Graphql 查询有疑问。从 DynamoDB table 获取 Items
后,我必须使用 Map 函数,然后 return 基于 Graphql type
的 Items
。我觉得这不是有效的方法。 Idk 查询数据的最佳方式。此外,作者和作者查询都为空。
这是我的gitlab-branch。
这是我的 Graphql 模式
import { gql } from 'apollo-server-lambda';
const typeDefs = gql`
enum Genre {
adventure
drama
scifi
}
enum Authors {
AUTHOR
}
# Root Query - all the queries supported by the schema
type Query {
"""
All Authors query
"""
authors(author: Authors): [Author]
books(book: String): [Book]
}
# Root Mutation - all the mutations supported by the schema
type Mutation {
createBook(input: CreateBook!): Book
}
"""
One Author can have many books
"""
type Author {
id: ID!
authorName: String
book: [Book]!
}
"""
Book Schema
"""
type Book {
id: ID!
name: String
price: String
publishingYear: String
publisher: String
author: [Author]
description: String
page: Int
genre: [Genre]
}
input CreateBook {
name: String
price: String
publishingYear: String
publisher: String
author: [CreateAuthor]
description: String
page: Int
genre: [Genre]
}
input CreateAuthor {
authorName: String!
}
`;
export default typeDefs;
这是我创建的图书项目
import AWS from 'aws-sdk';
import { v4 } from 'uuid';
import { CreateBook } from '../../generated/schema';
async function createBook(_: unknown, { input }: { input: CreateBook }) {
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const id = v4();
const authorsName =
input.author &&
input.author.map(function (item) {
return item['authorName'];
});
const params = {
TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
Item: {
PK: `AUTHOR`,
SK: `AUTHORS#${id}`,
GSI1PK: `BOOKS`,
GSI1SK: `BOOK#${input.name}`,
name: input.name,
author: authorsName,
price: input.price,
publishingYear: input.publishingYear,
publisher: input.publisher,
page: input.page,
description: input.description,
genre: input.genre,
},
};
await dynamoDb.put(params).promise();
return {
...input,
id,
};
}
export default createBook;
这是查询全书的方法
import AWS from 'aws-sdk';
async function books(_: unknown, input: { book: string }) {
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const params = {
TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
IndexName: 'GSI1',
KeyConditionExpression: 'GSI1PK = :hkey',
ExpressionAttributeValues: {
':hkey': `${input.book}`,
},
};
const { Items } = await dynamoDb.query(params).promise();
const allBooks = // NEED TO MAP THE FUNcTION THEN RETURN THE DATA BASED ON GRAPHQL //QUERIES.
Items &&
Items.map((i) => {
const genre = i.genre.filter((i) => i);
return {
name: i.name,
author: i.author,
genre,
};
});
return allBooks;
}
export default books;
这是我的作者查询和控制台结果的图像
import AWS from 'aws-sdk';
import { Author, Authors } from '../../generated/schema';
async function authors(
_: unknown,
input: { author: Authors }
): Promise<Author> {
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const params = {
TableName: process.env.ITEM_TABLE ? process.env.ITEM_TABLE : '',
KeyConditionExpression: 'PK = :hkey',
ExpressionAttributeValues: {
':hkey': `${input.author}`,
},
};
const { Items } = await dynamoDb.query(params).promise();
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
// type Author {
// id: ID!
// authorName: String
// book: [Book]!
// }
return Items; // return null in Graphql play ground.
}
export default authors;
编辑:当前解析器映射
// resolver map - src/resolvers/index.ts
const resolvers = {
Query: {
books,
authors,
author,
book,
},
Mutation: {
createBook,
},
};
TL;DR 您缺少一些解析器。您的查询解析器正在尝试完成缺少的解析器的工作。您的解析器必须 return 数据格式正确。
换句话说,您的问题出在配置 Apollo Server 的解析器上。据我所知,没有什么是特定于 Lambda 的。
编写并注册缺少的解析器。
例如,GraphQL 不知道如何“解析”作者的书籍。添加一个 Author {books(parent)}
条目到 Apollo Server 的 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 你可以适应。
这是一个重构的 author
查询,注释了将调用的解析器:
query author(id: '1') { # Query { author } resolver
authorName
books { # Author { books(parent) } resolver
name
authors { # Book { author(parent) } resolver
id
}
}
}
Apollo 服务器在查询执行期间使用解析器映射来决定为给定查询字段调用哪些解析器。地图看起来像您的模式并非巧合。使用 parent, arg, context and info 个参数调用解析器函数,这为您的函数提供了从数据源获取正确记录的上下文。
// resolver map - passed to the Apollo Server constructor
const resolvers = {
Query: {
books,
authors,
author,
book,
},
Author: {
books(parent) { getAuthorBooks(parent); }, // parent is the author - resolver should return a list of books
},
Book: {
authors(parent) { getBookAuthors(parent); }, // parent is the book - resolver should return a list of authors
},
};
您的查询解析器试图做太多的工作。
解析所有子字段不是作者查询解析器的工作。 Apollo Server 会多次调用多个解析器 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 服务器称其为 resolver chain。 books(parent)
解析器将以 Author
作为其 parent
参数被调用。可以用作者id查她的书
您的解析器 return 值必须与架构一致。
确保您的解析器return正在按照架构所需的形式处理数据。您的 author
解析器显然正在 return 映射 {Items: [author-record]}
,但您的模式说它需要是一个列表。
(如果我是你,我会将作者查询签名从 author(PK: String, SK: String): [Author]
更改为对调用者更友好的内容,例如 author(id: ID): Author
。Return 一个对象,而不是一个列表。隐藏解析器函数中的 DynamoDB 实现细节。Apollo Server 有一个 ID
标量类型,即 serialised as a String。)