surveygo
Go library for creating and managing surveys with validation, conditional logic, and rendering.
Import: github.com/rendis/surveygo/v2
Quick Start
// Parse survey from JSON
survey, err := surveygo.ParseFromJsonStr(jsonStr)
// Review answers
answers := surveygo.Answers{
"question1": {"answer_value"},
"choice_q": {"option_nameId"},
}
resume, err := survey.ReviewAnswers(answers)
// Translate choice nameIds to labels/values
translated, err := survey.TranslateAnswers(answers, false)
Core Workflows
Parse / Create Survey
// From JSON string or bytes
survey, err := surveygo.ParseFromJsonStr(jsonStr)
survey, err := surveygo.ParseFromBytes(jsonBytes)
// Programmatically
survey, err := surveygo.NewSurvey("My Survey", "1.0", nil)
Parsing auto-validates struct, checks consistency, and assigns positions.
Add Questions and Groups
// Add question from JSON
err := survey.AddQuestionJson(`{
"nameId": "fav_color",
"visible": true,
"type": "single_select",
"label": "Favorite color?",
"value": {
"options": [
{"nameId": "red", "label": "Red"},
{"nameId": "blue", "label": "Blue"}
]
}
}`)
// Assign question to group (position -1 = append)
err = survey.AddQuestionToGroup("fav_color", "my_group", -1)
// Add group
err = survey.AddGroupJson(`{"nameId": "my_group"}`)
survey.UpdateGroupsOrder([]string{"my_group", "other_group"})
All Add/Update methods have variants: *Question(q), *QuestionJson(s), *QuestionBytes(b), *QuestionMap(m).
Same for groups. Also AddOrUpdate* variants that upsert.
Review Answers
resume, err := survey.ReviewAnswers(answers)
// Check completion
fmt.Println(resume.TotalRequiredQuestionsAnswered, "/", resume.TotalRequiredQuestions)
// Check invalid answers
for _, inv := range resume.InvalidAnswers {
fmt.Printf("%s: %s\n", inv.QuestionNameId, inv.Error)
}
// Per-group stats
groupResume := resume.GroupsResume["group_nameId"]
Grouped (Repeatable) Answers
Groups with AllowRepeat: true accept multiple answer sets:
answers := surveygo.Answers{
"repeatable_group": {
map[string][]any{"q1": {"a1"}, "q2": {"a2"}}, // set 1
map[string][]any{"q1": {"b1"}, "q2": {"b2"}}, // set 2
},
}
DependsOn Conditional Logic
Questions/groups become visible only when referenced choice options are selected.
{
"dependsOn": [
[{ "questionNameId": "q1", "optionNameId": "opt_a" }],
[
{ "questionNameId": "q2", "optionNameId": "opt_b" },
{ "questionNameId": "q3", "optionNameId": "opt_c" }
]
]
}
- Outer array = OR (any group matches = visible)
- Inner array = AND (all conditions must match)
- Referenced question must be a choice type
- Invisible questions are excluded from
SurveyResumetotals
Rendering
import "github.com/rendis/surveygo/v2/render"
csvBytes, err := render.AnswersToCSV(survey, answers)
card, err := render.AnswersToJSON(survey, answers)
htmlResult, err := render.AnswersToHTML(survey, answers)
tiptap, err := render.AnswersToTipTap(survey, answers)
// Multi-format single pass
result, err := render.AnswersTo(survey, answers, render.OutputOptions{
CSV: true, JSON: true, HTML: true, TipTap: true,
})
// HTMLResult has separate HTML + CSS
htmlResult.WithCSSPath("/static/card.css") // replace CSS href
// Tabular matrix (header row + data rows, same data as CSV but as Go types)
matrix, err := render.AnswersToRows(survey, answers)
See references/render.md for full render API and typesGotchas
- Answers type: always
map[string][]any— values are arrays even for single answers - Choice answers: stored as option nameIds (strings). Use
TranslateAnswersto get labels/values - Asset MaxFiles/MinFiles:
0means default1, not unlimited/zero. The lib does NOT validate file counts — consuming apps must handle this - External questions: use direct type assertion
q.Value.(*external.ExternalQuestion)— noCastToExternalfunction exists - AnswerExpr: expr-lang/expr expression. Environment:
ans([]any) +options(map[nameId]label for choice types). Silent fallback on error (nil, false). Never writes to stderr - Group.Title: is
*string, notstring - NameId regex:
^[a-zA-Z][a-zA-Z\d_-]{1,62}[a-zA-Z\d]$(3-64 chars, start with letter, end with alphanumeric) - Position: auto-calculated — do not set manually
- Slider: is a choice type (complex) with
Min,Max,Step,Default,Unit— notOptions - RemoveQuestion: auto-cleans DependsOn references from other questions and groups
References
- references/api.md — Full API: all exported structs, methods, and function signatures
- references/question-types.md — All question types with their specific fields and cast functions
- references/render.md — Render package: output functions, types, and formats