Formbricks GraphQL API:查询调查数据教程
引言:为什么选择GraphQL查询调查数据?
你是否还在为整合多个REST API端点获取完整调查数据而烦恼?是否在面对复杂的嵌套数据结构时感到力不从心?本文将带你探索如何利用Formbricks GraphQL API高效查询调查数据,一次请求获取所有所需信息,显著提升数据获取效率。
读完本文后,你将能够:
- 理解Formbricks GraphQL API的核心优势
- 掌握GraphQL查询的基本语法和高级技巧
- 构建复杂的嵌套查询获取调查数据
- 处理和优化GraphQL查询性能
- 实现常见的调查数据分析场景
Formbricks GraphQL API概述
GraphQL vs REST:核心差异对比
| 特性 | GraphQL | REST |
|---|---|---|
| 请求数量 | 单次请求获取所有数据 | 多次请求不同端点 |
| 数据结构 | 按需定制返回结构 | 固定结构 |
| 版本控制 | 无需版本控制 | 通常需要(如v1, v2) |
| 类型系统 | 强类型,自文档化 | 松散类型,依赖外部文档 |
| 缓存机制 | 需额外实现 | 内置HTTP缓存 |
| 学习曲线 | 较陡峭 | 较平缓 |
Formbricks GraphQL API架构
Formbricks GraphQL API采用分层架构,主要包含以下组件:
- API网关:处理认证、请求验证和路由
- GraphQL解析器:解析查询并获取所需数据
- 数据服务层:实现业务逻辑和数据访问
- 数据库:存储所有调查相关数据
快速开始:首次查询
API端点与认证
Formbricks GraphQL API的主要端点为:
https://api.formbricks.com/graphql
认证方式采用Bearer Token,在请求头中添加:
Authorization: Bearer YOUR_API_KEY
获取API密钥:登录Formbricks账户,进入设置 > API集成 > 创建新API密钥,选择"读取调查数据"权限。
第一个查询:获取调查列表
query GetSurveys {
surveys {
id
name
description
status
createdAt
updatedAt
questionCount
}
}
响应示例:
{
"data": {
"surveys": [
{
"id": "surv_123456",
"name": "用户满意度调查",
"description": "评估用户对我们产品的满意度",
"status": "PUBLISHED",
"createdAt": "2025-08-15T10:30:00Z",
"updatedAt": "2025-08-16T14:20:00Z",
"questionCount": 8
},
{
"id": "surv_789012",
"name": "功能使用频率调查",
"description": "了解用户使用各功能的频率",
"status": "DRAFT",
"createdAt": "2025-08-20T09:15:00Z",
"updatedAt": "2025-08-20T09:15:00Z",
"questionCount": 5
}
]
}
}
核心查询操作
获取单个调查详情
query GetSurveyDetails($surveyId: ID!) {
survey(id: $surveyId) {
id
name
description
status
createdAt
updatedAt
questions {
id
text
type
options {
id
text
value
}
required
position
}
audience {
totalCount
completedCount
responseRate
}
}
}
变量:
{
"surveyId": "surv_123456"
}
查询调查响应数据
query GetSurveyResponses($surveyId: ID!, $limit: Int = 10, $offset: Int = 0) {
surveyResponses(surveyId: $surveyId, limit: $limit, offset: $offset) {
totalCount
responses {
id
personId
completed
startedAt
completedAt
answers {
questionId
questionText
value
selectedOptions {
id
text
}
}
metadata {
userAgent
ipAddress
deviceType
browser
operatingSystem
}
}
}
}
高级过滤与排序
query FilteredSurveys {
surveys(
filter: {
status: PUBLISHED
createdAt: { greaterThan: "2025-01-01T00:00:00Z" }
questionCount: { greaterThan: 5 }
}
sort: { field: CREATED_AT, direction: DESC }
limit: 20
) {
id
name
createdAt
questionCount
responseCount
}
}
高级查询技巧
嵌套查询与片段
fragment QuestionDetails on Question {
id
text
type
required
position
}
fragment AnswerDetails on Answer {
questionId
questionText
value
selectedOptions {
id
text
}
}
query GetSurveyWithResponses($surveyId: ID!) {
survey(id: $surveyId) {
id
name
questions {
...QuestionDetails
}
responses(limit: 5) {
id
personId
completedAt
answers {
...AnswerDetails
}
}
}
}
条件查询与别名
query SurveyAnalytics($surveyId: ID!) {
publishedSurvey: survey(id: $surveyId) {
id
name
status
responseRate
averageCompletionTime
}
draftSurveys: surveys(filter: { status: DRAFT }) {
id
name
createdAt
}
}
聚合查询与统计数据
query SurveyStatistics($surveyId: ID!) {
surveyStatistics(surveyId: $surveyId) {
totalResponses
completedResponses
incompleteResponses
averageTimeToComplete
responseRate
completionRate
questionStatistics {
questionId
questionText
responseCount
skipRate
averageResponseTime
}
}
}
常见查询场景
场景一:获取调查结果摘要
query SurveyResultsSummary($surveyId: ID!) {
survey(id: $surveyId) {
id
name
questions {
id
text
type
options {
id
text
responseCount
percentage
}
averageRating # 适用于评分类型问题
textResponses(limit: 5) { # 适用于文本类型问题
id
value
createdAt
}
}
}
}
场景二:用户响应追踪
query PersonSurveyResponses($personId: ID!) {
person(id: $personId) {
id
name
email
surveys {
id
name
status
response {
id
completed
startedAt
completedAt
answers {
questionId
questionText
value
}
}
}
}
}
场景三:时间序列分析
query ResponseTimeSeries($surveyId: ID!) {
responseTimeSeries(surveyId: $surveyId, interval: DAILY) {
date
newResponses
completedResponses
cumulativeResponses
}
}
响应示例:
{
"data": {
"responseTimeSeries": [
{
"date": "2025-08-01",
"newResponses": 15,
"completedResponses": 12,
"cumulativeResponses": 12
},
{
"date": "2025-08-02",
"newResponses": 28,
"completedResponses": 25,
"cumulativeResponses": 37
},
// 更多日期数据...
]
}
}
查询性能优化
分页策略
Formbricks GraphQL API支持两种分页方式:
- 偏移分页(适用于小型数据集):
query PaginatedResponses($surveyId: ID!, $limit: Int!, $offset: Int!) {
surveyResponses(surveyId: $surveyId, limit: $limit, offset: $offset) {
totalCount
responses {
id
personId
completedAt
}
}
}
- 游标分页(适用于大型数据集):
query CursorPaginatedResponses($surveyId: ID!, $first: Int!, $after: String) {
surveyResponses(surveyId: $surveyId, first: $first, after: $after) {
pageInfo {
hasNextPage
endCursor
}
edges {
cursor
node {
id
personId
completedAt
}
}
}
}
查询复杂度与深度限制
Formbricks GraphQL API实施查询复杂度限制,默认最大复杂度为1000,深度限制为10级。可以通过以下方式优化复杂查询:
- 拆分大型查询为多个小型查询
- 使用片段复用常用字段集
- 限制嵌套深度,避免过深的嵌套查询
- 指定确切字段,避免请求不必要的数据
缓存策略
推荐的缓存策略:
- 使用Apollo Client等客户端库自动管理缓存
- 为频繁查询添加
cacheControl指令 - 实现基于实体ID的规范化缓存
错误处理与调试
常见错误类型及解决方案
| 错误类型 | 错误信息示例 | 解决方案 |
|---|---|---|
| 认证错误 | "未授权访问" | 检查API密钥是否有效,权限是否正确 |
| 格式错误 | "语法错误在位置123" | 验证GraphQL语法,使用GraphQL Playground调试 |
| 字段不存在 | "无法查询字段'xyz'在类型'Survey'" | 检查字段名称是否正确,参考API文档 |
| 速率限制 | "已超出速率限制" | 实现请求限流,或联系支持提升限制 |
| 复杂度超限 | "查询复杂度超出限制" | 简化查询,减少请求字段或嵌套深度 |
使用GraphQL Playground
Formbricks提供交互式GraphQL Playground:
https://api.formbricks.com/graphql/playground
主要功能:
- 交互式查询编辑和执行
- 自动补全和语法高亮
- 文档浏览和类型检查
- 查询历史记录
- 响应格式化和分析
最佳实践与性能优化
查询设计原则
- 只请求需要的字段:避免使用
... on获取所有字段 - 使用变量:而非硬编码值,提高复用性和安全性
- 分页处理:避免一次请求过多数据
- 监控查询性能:使用
@debug指令分析慢查询 - 批量请求:合并多个相关查询,减少网络往返
代码示例:使用Apollo Client集成
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
// 初始化Apollo客户端
const client = new ApolloClient({
uri: 'https://api.formbricks.com/graphql',
cache: new InMemoryCache(),
headers: {
authorization: `Bearer ${process.env.FORMBRICKS_API_KEY}`,
},
});
// 定义查询
const GET_SURVEY_RESULTS = gql`
query GetSurveyResults($surveyId: ID!) {
survey(id: $surveyId) {
id
name
questions {
id
text
type
options {
id
text
responseCount
percentage
}
}
}
}
`;
// 执行查询
async function fetchSurveyResults(surveyId) {
try {
const result = await client.query({
query: GET_SURVEY_RESULTS,
variables: { surveyId },
});
return result.data.survey;
} catch (error) {
console.error('Error fetching survey results:', error);
throw error;
}
}
性能优化清单
- 使用精确字段选择,避免过度请求
- 实现分页加载大型数据集
- 添加适当的缓存策略
- 监控和优化慢查询
- 避免N+1查询问题
- 使用批量操作处理多个实体
高级应用:数据可视化集成
示例:使用Chart.js可视化调查结果
<!DOCTYPE html>
<html>
<head>
<title>Formbricks调查结果可视化</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@apollo/client@3.10.4/dist/main.umd.min.js"></script>
</head>
<body>
<canvas id="surveyChart" width="400" height="400"></canvas>
<script>
// 初始化Apollo客户端
const client = new ApolloClient({
uri: 'https://api.formbricks.com/graphql',
cache: new InMemoryCache(),
headers: {
authorization: `Bearer YOUR_API_KEY`,
},
});
// GraphQL查询
const GET_SURVEY_DATA = gql`
query GetSurveyData($surveyId: ID!) {
survey(id: $surveyId) {
id
name
questions {
id
text
options {
id
text
responseCount
}
}
}
}
`;
// 获取并可视化数据
client.query({
query: GET_SURVEY_DATA,
variables: { surveyId: 'surv_123456' }
}).then(result => {
const survey = result.data.survey;
const firstQuestion = survey.questions[0];
// 准备图表数据
const labels = firstQuestion.options.map(option => option.text);
const data = firstQuestion.options.map(option => option.responseCount);
// 创建图表
new Chart(
document.getElementById('surveyChart'),
{
type: 'bar',
data: {
labels: labels,
datasets: [{
label: firstQuestion.text,
data: data,
backgroundColor: 'rgba(54, 162, 235, 0.5)'
}]
}
}
);
});
</script>
</body>
</html>
总结与展望
核心知识点回顾
- Formbricks GraphQL API提供了灵活的数据查询能力,支持按需获取调查数据
- 基本查询结构包括查询名称、变量、字段和片段
- 认证使用Bearer Token,需正确配置API密钥和权限
- 常见查询场景包括调查列表、详情、结果统计和用户响应
- 性能优化关键在于合理设计查询、实现分页和使用缓存
高级功能预告
Formbricks团队正在开发以下GraphQL API高级功能:
- 实时订阅(使用WebSocket)获取调查响应更新
- 批量操作API,支持同时更新多个实体
- 自定义报告生成和导出
- 高级分析和预测功能
学习资源
- 官方文档:https://docs.formbricks.com/graphql-api
- GraphQL规范:https://spec.graphql.org/
- Apollo Client文档:https://www.apollographql.com/docs/react/
- GraphQL学习平台:https://graphql.org/learn/
如果你有任何问题或需要进一步帮助,请访问Formbricks社区论坛或联系技术支持。
附录:完整类型定义参考
type Survey {
id: ID!
name: String!
description: String
status: SurveyStatus!
createdAt: DateTime!
updatedAt: DateTime!
questions: [Question!]!
responses: [Response!]!
responseCount: Int!
completionRate: Float!
averageTimeToComplete: Int
# 更多字段...
}
enum SurveyStatus {
DRAFT
PUBLISHED
ARCHIVED
SCHEDULED
}
type Question {
id: ID!
text: String!
description: String
type: QuestionType!
required: Boolean!
position: Int!
options: [QuestionOption!]
# 更多字段...
}
enum QuestionType {
TEXT
PARAGRAPH
MULTIPLE_CHOICE
CHECKBOX
DROPDOWN
RATING
DATE
EMAIL
NUMBER
}
# 更多类型定义...
希望本教程能帮助你充分利用Formbricks GraphQL API查询和分析调查数据。如有任何问题或建议,请在评论区留言或联系我们的支持团队。
如果你觉得本教程有帮助,请点赞并分享给其他Formbricks用户!下期我们将探讨如何使用GraphQL mutations创建和更新调查数据。```markdown
Formbricks GraphQL API:查询调查数据教程
引言:为什么选择GraphQL查询调查数据
你是否还在为整合多个REST API端点获取完整调查数据而烦恼?是否在面对复杂的嵌套数据结构时感到力不从心?本文将带你探索如何利用Formbricks GraphQL API高效查询调查数据,一次请求获取所有所需信息,显著提升数据获取效率。
读完你能得到:
- 理解Formbricks GraphQL API的核心优势与架构
- 掌握从基础到高级的查询语法与最佳实践
- 实现常见调查数据分析场景的完整查询示例
- 优化查询性能的实用技巧与工具集成方案
GraphQL vs REST:核心差异对比
| 特性 | GraphQL | REST |
|---|---|---|
| 请求数量 | 单次请求获取所有数据 | 需多次请求不同端点 |
| 数据结构 | 按需定制返回字段 | 服务端定义固定结构 |
| 版本控制 | 无需版本控制,平滑演进 | 通常需要版本号(如v1/v2) |
| 类型系统 | 强类型,自文档化schema | 依赖外部文档,类型松散 |
| 学习曲线 | 较陡峭,需理解查询语法 | 平缓,基于HTTP标准方法 |
Formbricks GraphQL API架构
Formbricks GraphQL API采用分层架构设计,确保数据查询的高效性和安全性:
- 认证层:验证API密钥与请求权限
- 解析器层:将GraphQL查询转换为数据获取操作
- 业务逻辑层:实现调查数据的权限校验与处理
- 数据访问层:与数据库交互获取原始数据
快速开始:首次查询
API端点与认证
Formbricks GraphQL API的标准端点为:
https://api.formbricks.com/graphql
认证方式采用Bearer Token机制,在HTTP请求头中添加:
Authorization: Bearer YOUR_API_KEY
获取API密钥流程:登录Formbricks控制台 → 进入组织设置 → API集成 → 创建新密钥 → 选择"调查数据读取"权限范围
第一个查询:获取调查列表
query GetSurveys {
surveys {
id
name
description
status
createdAt
questionCount
responseCount
}
}
响应示例:
{
"data": {
"surveys": [
{
"id": "surv_123456",
"name": "产品满意度调查",
"description": "2025年第二季度用户满意度评估",
"status": "PUBLISHED",
"createdAt": "2025-06-15T08:30:00Z",
"questionCount": 8,
"responseCount": 247
},
{
"id": "surv_789012",
"name": "功能使用频率调查",
"description": "了解用户对各功能模块的使用情况",
"status": "PUBLISHED",
"createdAt": "2025-06-20T14:15:00Z",
"questionCount": 12,
"responseCount": 183
}
]
}
}
核心查询操作详解
获取单个调查详情
query GetSurveyDetails($surveyId: ID!) {
survey(id: $surveyId) {
id
name
description
status
createdAt
updatedAt
questions {
id
text
type
required
position
options {
id
text
value
}
}
metadata {
totalResponses
completedResponses
responseRate
averageCompletionTime
}
}
}
查询变量:
{
"surveyId": "surv_123456"
}
分页查询调查响应
query GetSurveyResponses($surveyId: ID!, $limit: Int = 20, $offset: Int = 0) {
surveyResponses(
surveyId: $surveyId
pagination: { limit: $limit, offset: $offset }
filter: { completed: true }
) {
totalCount
responses {
id
personId
startedAt
completedAt
answers {
questionId
questionText
value
selectedOptions {
id
text
}
}
}
}
}
高级过滤与排序
query FilteredSurveys {
surveys(
filter: {
status: PUBLISHED
createdAt: { greaterThan: "2025-01-01T00:00:00Z" }
responseCount: { greaterThan: 100 }
}
sort: { field: CREATED_AT, direction: DESC }
pagination: { limit: 10 }
) {
id
name
createdAt
responseCount
completionRate
}
}
高级查询技巧
片段复用与嵌套查询
fragment QuestionFields on Question {
id
text
type
required
position
description
}
fragment AnswerFields on Answer {
questionId
questionText
value
displayValue
createdAt
}
query SurveyWithDetailedResponses($surveyId: ID!) {
survey(id: $surveyId) {
id
name
questions {
...QuestionFields
options {
id
text
value
responseCount
}
}
recentResponses(limit: 5) {
id
person {
id
email
createdAt
}
startedAt
completedAt
answers {
...AnswerFields
}
}
}
}
条件查询与别名
query MultiSurveyData {
activeSurveys: surveys(filter: { status: PUBLISHED }) {
id
name
responseCount
}
draftSurveys: surveys(filter: { status: DRAFT }) {
id
name
updatedAt
}
highResponseSurvey: survey(id: "surv_123456") {
id
name
responseRate
averageCompletionTime
}
}
聚合统计查询
query SurveyStatistics($surveyId: ID!) {
surveyStatistics(surveyId: $surveyId) {
totalResponses
completedResponses
incompleteResponses
completionRate
averageTimeToComplete
questionBreakdown {
questionId
questionText
responseCount
skipRate
averageResponseTime
options {
id
text
selectedCount
percentage
}
}
}
}
常见查询场景实现
场景一:获取调查结果摘要
query SurveyResultsSummary($surveyId: ID!) {
survey(id: $surveyId) {
id
name
status
createdAt
questionCount
responseCount
questions {
id
text
type
... on RatingQuestion {
averageRating
ratingDistribution {
value
count
percentage
}
}
... on MultipleChoiceQuestion {
options {
id
text
selectedCount
percentage
}
}
... on TextQuestion {
responseCount
sampleResponses(limit: 3) {
id
value
createdAt
}
}
}
}
}
场景二:用户参与度分析
query PersonSurveyJourney($personId: ID!) {
person(id: $personId) {
id
email
createdAt
surveys {
id
name
status
response {
id
startedAt
completedAt
timeToComplete
answers {
questionId
questionText
value
}
}
invitation {
sentAt
openedAt
clickedAt
}
}
}
}
场景三:时间序列响应分析
query ResponseTimeSeries($surveyId: ID!) {
surveyResponseTimeSeries(
surveyId: $surveyId
interval: DAILY
dateRange: {
start: "2025-06-01T00:00:00Z"
end: "2025-06-30T23:59:59Z"
}
) {
date
newResponses
completedResponses
cumulativeResponses
averageCompletionTime
}
}
查询性能优化
分页策略对比
| 分页类型 | 适用场景 | 实现方式 | 优缺点 |
|---|---|---|---|
| Offset分页 | 小型数据集,随机访问 | limit + offset参数 | 实现简单,但大数据集性能差 |
| 游标分页 | 大型数据集,顺序访问 | first + after参数 | 性能优异,支持无限滚动 |
| 键集分页 | 大数据集,范围查询 | 基于唯一排序字段 | 查询稳定,无偏移异常 |
游标分页实现示例:
query CursorPaginatedResponses($surveyId: ID!, $first: Int, $after: String) {
surveyResponses(
surveyId: $surveyId
first: $first
after: $after
) {
pageInfo {
hasNextPage
endCursor
}
edges {
cursor
node {
id
personId
completedAt
answers {
questionId
value
}
}
}
}
}
查询复杂度控制
Formbricks GraphQL API实施查询复杂度限制(默认最大复杂度为1000),以下是优化复杂度的实用技巧:
- 限制字段数量:只请求必要字段,避免使用
...获取所有字段 - 控制嵌套深度:建议嵌套层级不超过3层
- 使用分片查询:将复杂查询拆分为多个简单查询
- 添加查询注释:使用
# @complexity 50指定预期复杂度
query OptimizedSurveyQuery {
surveys(pagination: { limit: 5 }) { # 复杂度:10
id
name
responses(pagination: { limit: 10 }) { # 复杂度:50 (5*10)
id
personId
# 仅请求必要的answer字段,降低复杂度
answers(pagination: { limit: 5 }) { # 复杂度:250 (5*10*5)
questionId
value
}
}
}
}
# 总复杂度:310,远低于1000的上限
缓存实现策略
推荐缓存方案:
- 使用Apollo Client自动管理查询缓存
- 实现基于实体ID的规范化存储
- 为频繁查询添加
@cacheControl(maxAge: 3600)指令 - 对实时性要求高的数据使用
fetchPolicy: "network-only"
错误处理与调试
常见错误及解决方案
| 错误类型 | 典型消息 | 解决方案 |
|---|---|---|
| 认证失败 | "Invalid API key" | 检查密钥有效性,确认未过期 |
| 权限不足 | "Insufficient permissions" | 验证API密钥是否包含"调查读取"权限 |
| 语法错误 | "Syntax Error: Expected Name" | 使用GraphQL Playground验证语法 |
| 字段不存在 | "Cannot query field 'xyz' on type 'Survey'" | 检查字段名拼写,参考自动生成文档 |
| 复杂度超限 | "Query complexity exceeds maximum" | 简化查询,减少字段和嵌套层级 |
使用GraphQL Playground调试
Formbricks提供交互式调试环境:
https://api.formbricks.com/graphql/playground
主要调试功能:
- 实时语法验证与错误提示
- 自动补全与文档提示
- 查询变量管理
- 响应格式化与分析
- 请求头配置与认证管理
代码集成示例
JavaScript/TypeScript集成(Apollo Client)
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
// 初始化客户端
const client = new ApolloClient({
uri: 'https://api.formbricks.com/graphql',
cache: new InMemoryCache(),
headers: {
authorization: `Bearer ${process.env.FORMBRICKS_API_KEY}`,
},
});
// 定义查询
const GET_SURVEY_RESULTS = gql`
query GetSurveyResults($surveyId: ID!) {
survey(id: $surveyId) {
id
name
questions {
id
text
type
options {
id
text
responseCount
percentage
}
... on RatingQuestion {
averageRating
}
}
}
}
`;
// 执行查询
async function loadSurveyResults(surveyId) {
try {
const { data } = await client.query({
query: GET_SURVEY_RESULTS,
variables: { surveyId },
});
return data.survey;
} catch (error) {
console.error('Error loading survey results:', error);
throw error;
}
}
Python集成(GQL客户端)
from gql import Client, gql
from gql.transport.requests import RequestsHTTPTransport
# 设置传输层
transport = RequestsHTTPTransport(
url="https://api.formbricks.com/graphql",
headers={"Authorization": "Bearer YOUR_API_KEY"},
use_json=True,
)
# 初始化客户端
client = Client(transport=transport, fetch_schema_from_transport=True)
# 定义查询
query = gql("""
query GetSurveyList {
surveys(pagination: { limit: 5 }) {
id
name
responseCount
completionRate
}
}
""")
# 执行查询
result = client.execute(query)
print(result)
最佳实践总结
查询设计 checklist
- 始终使用变量而非硬编码值
- 限制分页大小,避免一次请求过多数据
- 使用片段复用常用字段集
- 为查询添加描述性名称,便于调试
- 实现错误处理与重试机制
- 对敏感字段(如个人信息)实施过滤
性能优化 checklist
- 监控查询响应时间,识别慢查询
- 实施查询缓存策略
- 避免N+1查询问题(使用dataloader模式)
- 定期审查和优化常用查询
- 使用批量操作减少请求次数
- 合理设置分页大小(建议20-50条/页)
附录:常用查询片段库
调查基础信息片段
fragment SurveyInfo on Survey {
id
name
description
status
createdAt
updatedAt
questionCount
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



