Skip to content

Basic Examples

This page provides practical examples for common H5P Go SDK usage patterns.

Simple Quiz Creation

Basic Multiple Choice Quiz

package main

import (
    "fmt"
    "log"
    "os"

    "github.com/grokify/h5p-go"
)

func main() {
    // Create a simple geography quiz
    quiz := createGeographyQuiz()

    // Export to JSON file
    jsonData, err := quiz.ToJSON()
    if err != nil {
        log.Fatal("JSON export failed:", err)
    }

    err = os.WriteFile("geography-quiz.json", jsonData, 0644)
    if err != nil {
        log.Fatal("File write failed:", err)
    }

    fmt.Println("Geography quiz created successfully!")
    fmt.Printf("Title: %s\n", quiz.Title)
    fmt.Printf("Questions: %d\n", len(quiz.Questions))
    fmt.Printf("Pass percentage: %d%%\n", quiz.PassPercentage)
}

func createGeographyQuiz() *h5p.QuestionSet {
    builder := h5p.NewQuestionSetBuilder()

    // Question 1: Capital cities
    capitalAnswers := []h5p.Answer{
        h5p.CreateAnswerWithFeedback("Paris", true, "Correct! Paris is the capital of France."),
        h5p.CreateAnswerWithFeedback("London", false, "London is the capital of the United Kingdom."),
        h5p.CreateAnswerWithFeedback("Berlin", false, "Berlin is the capital of Germany."),
        h5p.CreateAnswerWithFeedback("Madrid", false, "Madrid is the capital of Spain."),
    }

    // Question 2: Continents
    continentAnswers := []h5p.Answer{
        h5p.CreateAnswerWithFeedback("Asia", true, "Correct! Asia is the largest continent."),
        h5p.CreateAnswerWithFeedback("Africa", false, "Africa is the second largest continent."),
        h5p.CreateAnswerWithFeedback("North America", false, "North America is the third largest."),
        h5p.CreateAnswerWithFeedback("Europe", false, "Europe is much smaller than Asia."),
    }

    // Question 3: Oceans
    oceanAnswers := []h5p.Answer{
        h5p.CreateAnswerWithFeedback("Pacific Ocean", true, "Correct! The Pacific is the largest ocean."),
        h5p.CreateAnswerWithFeedback("Atlantic Ocean", false, "The Atlantic is the second largest."),
        h5p.CreateAnswerWithFeedback("Indian Ocean", false, "The Indian Ocean is the third largest."),
        h5p.CreateAnswerWithFeedback("Arctic Ocean", false, "The Arctic Ocean is the smallest."),
    }

    // Overall feedback based on performance
    feedback := []h5p.OverallFeedback{
        {
            From:     0,
            To:       40,
            Feedback: "Keep studying geography! There's so much to learn about our world.",
        },
        {
            From:     41,
            To:       70,
            Feedback: "Good job! You have solid basic geography knowledge.",
        },
        {
            From:     71,
            To:       100,
            Feedback: "Excellent! You're a geography expert!",
        },
    }

    // Build the complete quiz
    questionSet, err := builder.
        SetTitle("Basic Geography Quiz").
        SetProgressType("textual").
        SetPassPercentage(60).
        SetIntroduction("Test your knowledge of world geography with this fun quiz!").
        SetStartButtonText("Start Quiz").
        AddMultipleChoiceQuestion("What is the capital of France?", capitalAnswers).
        AddMultipleChoiceQuestion("Which is the largest continent by area?", continentAnswers).
        AddMultipleChoiceQuestion("What is the largest ocean on Earth?", oceanAnswers).
        AddOverallFeedback(feedback).
        Build()

    if err != nil {
        log.Fatal("Failed to build quiz:", err)
    }

    return questionSet
}

Loading and Modifying Existing Content

Load and Update Quiz

package main

import (
    "fmt"
    "log"
    "os"

    "github.com/grokify/h5p-go"
)

func main() {
    // Load existing quiz from JSON file
    quiz, err := loadQuizFromFile("existing-quiz.json")
    if err != nil {
        log.Fatal("Failed to load quiz:", err)
    }

    fmt.Printf("Loaded quiz: %s\n", quiz.Title)
    fmt.Printf("Original questions: %d\n", len(quiz.Questions))

    // Add a new question
    newAnswers := []h5p.Answer{
        h5p.CreateAnswer("7", false),
        h5p.CreateAnswer("8", true),
        h5p.CreateAnswer("9", false),
        h5p.CreateAnswer("10", false),
    }

    // Create new question
    newQuestion := h5p.Question{
        Library: "H5P.MultiChoice 1.16",
        Params: map[string]interface{}{
            "question": "What is 4 + 4?",
            "answers":  convertAnswersToParams(newAnswers),
        },
    }

    // Add to existing quiz
    quiz.Questions = append(quiz.Questions, newQuestion)

    // Update title
    quiz.Title = "Updated " + quiz.Title

    // Validate modified quiz
    if err := quiz.Validate(); err != nil {
        log.Fatal("Modified quiz validation failed:", err)
    }

    // Save updated quiz
    jsonData, err := quiz.ToJSON()
    if err != nil {
        log.Fatal("JSON export failed:", err)
    }

    err = os.WriteFile("updated-quiz.json", jsonData, 0644)
    if err != nil {
        log.Fatal("File write failed:", err)
    }

    fmt.Printf("Updated quiz saved with %d questions\n", len(quiz.Questions))
}

func loadQuizFromFile(filename string) (*h5p.QuestionSet, error) {
    jsonData, err := os.ReadFile(filename)
    if err != nil {
        return nil, err
    }

    quiz, err := h5p.FromJSON(jsonData)
    if err != nil {
        return nil, err
    }

    // Validate loaded content
    if err := quiz.Validate(); err != nil {
        return nil, fmt.Errorf("loaded quiz is invalid: %w", err)
    }

    return quiz, nil
}

func convertAnswersToParams(answers []h5p.Answer) []map[string]interface{} {
    params := make([]map[string]interface{}, len(answers))
    for i, answer := range answers {
        params[i] = map[string]interface{}{
            "text":    answer.Text,
            "correct": answer.Correct,
        }
        if answer.Feedback != "" {
            params[i]["feedback"] = answer.Feedback
        }
    }
    return params
}

Working with Different Question Types

True/False Questions

func createTrueFalseQuiz() *h5p.QuestionSet {
    builder := h5p.NewQuestionSetBuilder()

    // True/False questions have exactly 2 answers
    question1Answers := []h5p.Answer{
        h5p.CreateAnswerWithFeedback("True", true, "Correct! The Earth is indeed round."),
        h5p.CreateAnswerWithFeedback("False", false, "Incorrect. The Earth is approximately spherical."),
    }

    question2Answers := []h5p.Answer{
        h5p.CreateAnswerWithFeedback("True", false, "Incorrect. Water boils at 100°C, not freezes."),
        h5p.CreateAnswerWithFeedback("False", true, "Correct! Water freezes at 0°C."),
    }

    questionSet, err := builder.
        SetTitle("True or False Science Quiz").
        SetProgressType("dots").
        SetPassPercentage(50).
        SetIntroduction("Test your science knowledge with these true/false questions.").
        AddMultipleChoiceQuestion("The Earth is round.", question1Answers).
        AddMultipleChoiceQuestion("Water freezes at 100 degrees Celsius.", question2Answers).
        Build()

    if err != nil {
        log.Fatal("Failed to build true/false quiz:", err)
    }

    return questionSet
}

Multi-Select Questions

func createMultiSelectQuiz() *h5p.QuestionSet {
    builder := h5p.NewQuestionSetBuilder()

    // Multiple correct answers
    programmingAnswers := []h5p.Answer{
        h5p.CreateAnswer("Go", true),        // Correct
        h5p.CreateAnswer("Python", true),    // Correct  
        h5p.CreateAnswer("Java", true),      // Correct
        h5p.CreateAnswer("HTML", false),     // Not a programming language
        h5p.CreateAnswer("CSS", false),      // Not a programming language
    }

    // Single correct answer for comparison
    capitalAnswers := []h5p.Answer{
        h5p.CreateAnswer("Tokyo", true),
        h5p.CreateAnswer("Osaka", false),
        h5p.CreateAnswer("Kyoto", false),
    }

    questionSet, err := builder.
        SetTitle("Mixed Question Types").
        SetProgressType("textual").
        SetPassPercentage(70).
        SetIntroduction("This quiz has both single-answer and multiple-answer questions.").
        AddMultipleChoiceQuestion("Which of these are programming languages? (Select all that apply)", programmingAnswers).
        AddMultipleChoiceQuestion("What is the capital of Japan?", capitalAnswers).
        Build()

    if err != nil {
        log.Fatal("Failed to build multi-select quiz:", err)
    }

    return questionSet
}

Error Handling Patterns

Comprehensive Error Handling

func createQuizWithErrorHandling() (*h5p.QuestionSet, error) {
    builder := h5p.NewQuestionSetBuilder()

    // Validate inputs before building
    title := "Programming Quiz"
    if title == "" {
        return nil, fmt.Errorf("quiz title cannot be empty")
    }

    passPercentage := 75
    if passPercentage < 0 || passPercentage > 100 {
        return nil, fmt.Errorf("pass percentage must be between 0 and 100, got %d", passPercentage)
    }

    // Create answers with validation
    answers, err := createValidatedAnswers()
    if err != nil {
        return nil, fmt.Errorf("failed to create answers: %w", err)
    }

    // Build with error handling
    questionSet, err := builder.
        SetTitle(title).
        SetProgressType("textual").
        SetPassPercentage(passPercentage).
        SetIntroduction("Welcome to the programming quiz!").
        AddMultipleChoiceQuestion("What is Go?", answers).
        Build()

    if err != nil {
        return nil, fmt.Errorf("failed to build question set: %w", err)
    }

    // Additional validation
    if len(questionSet.Questions) == 0 {
        return nil, fmt.Errorf("question set must have at least one question")
    }

    // Final validation
    if err := questionSet.Validate(); err != nil {
        return nil, fmt.Errorf("question set validation failed: %w", err)
    }

    return questionSet, nil
}

func createValidatedAnswers() ([]h5p.Answer, error) {
    answers := []h5p.Answer{
        {Text: "A programming language", Correct: true},
        {Text: "A database", Correct: false},
        {Text: "An operating system", Correct: false},
        {Text: "A web browser", Correct: false},
    }

    // Validate answers
    if len(answers) < 2 {
        return nil, fmt.Errorf("need at least 2 answers")
    }

    hasCorrect := false
    for i, answer := range answers {
        if answer.Text == "" {
            return nil, fmt.Errorf("answer %d has empty text", i+1)
        }
        if answer.Correct {
            hasCorrect = true
        }
    }

    if !hasCorrect {
        return nil, fmt.Errorf("at least one answer must be correct")
    }

    return answers, nil
}

Batch Processing

Create Multiple Quizzes

func createMultipleQuizzes() error {
    quizData := []struct {
        title     string
        questions []QuestionData
    }{
        {
            title: "Math Quiz",
            questions: []QuestionData{
                {
                    text: "What is 2 + 2?",
                    answers: []AnswerData{
                        {text: "4", correct: true},
                        {text: "3", correct: false},
                        {text: "5", correct: false},
                    },
                },
            },
        },
        {
            title: "Science Quiz",
            questions: []QuestionData{
                {
                    text: "What is H2O?",
                    answers: []AnswerData{
                        {text: "Water", correct: true},
                        {text: "Hydrogen", correct: false},
                        {text: "Oxygen", correct: false},
                    },
                },
            },
        },
    }

    for i, data := range quizData {
        quiz, err := buildQuizFromData(data)
        if err != nil {
            return fmt.Errorf("failed to create quiz %d: %w", i+1, err)
        }

        filename := fmt.Sprintf("quiz-%d.json", i+1)
        if err := exportQuiz(quiz, filename); err != nil {
            return fmt.Errorf("failed to export quiz %d: %w", i+1, err)
        }

        fmt.Printf("Created %s\n", filename)
    }

    return nil
}

type QuestionData struct {
    text    string
    answers []AnswerData
}

type AnswerData struct {
    text     string
    correct  bool
    feedback string
}

func buildQuizFromData(data struct {
    title     string
    questions []QuestionData
}) (*h5p.QuestionSet, error) {
    builder := h5p.NewQuestionSetBuilder().
        SetTitle(data.title).
        SetProgressType("textual").
        SetPassPercentage(60)

    for _, q := range data.questions {
        answers := make([]h5p.Answer, len(q.answers))
        for i, a := range q.answers {
            answers[i] = h5p.Answer{
                Text:     a.text,
                Correct:  a.correct,
                Feedback: a.feedback,
            }
        }

        builder = builder.AddMultipleChoiceQuestion(q.text, answers)
    }

    return builder.Build()
}

func exportQuiz(quiz *h5p.QuestionSet, filename string) error {
    jsonData, err := quiz.ToJSON()
    if err != nil {
        return err
    }

    return os.WriteFile(filename, jsonData, 0644)
}

Integration Examples

Web API Integration

// HTTP handler for creating quizzes
func createQuizHandler(w http.ResponseWriter, r *http.Request) {
    var request struct {
        Title      string `json:"title"`
        Questions  []struct {
            Text    string `json:"text"`
            Answers []struct {
                Text     string `json:"text"`
                Correct  bool   `json:"correct"`
                Feedback string `json:"feedback,omitempty"`
            } `json:"answers"`
        } `json:"questions"`
        PassPercentage int `json:"passPercentage"`
    }

    if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
        http.Error(w, "Invalid JSON", http.StatusBadRequest)
        return
    }

    // Build quiz from request
    builder := h5p.NewQuestionSetBuilder().
        SetTitle(request.Title).
        SetProgressType("textual").
        SetPassPercentage(request.PassPercentage)

    for _, q := range request.Questions {
        answers := make([]h5p.Answer, len(q.Answers))
        for i, a := range q.Answers {
            answers[i] = h5p.Answer{
                Text:     a.Text,
                Correct:  a.Correct,
                Feedback: a.Feedback,
            }
        }

        builder = builder.AddMultipleChoiceQuestion(q.Text, answers)
    }

    quiz, err := builder.Build()
    if err != nil {
        http.Error(w, fmt.Sprintf("Build failed: %v", err), http.StatusBadRequest)
        return
    }

    // Validate
    if err := quiz.Validate(); err != nil {
        http.Error(w, fmt.Sprintf("Validation failed: %v", err), http.StatusBadRequest)
        return
    }

    // Return JSON
    w.Header().Set("Content-Type", "application/json")
    jsonData, _ := quiz.ToJSON()
    w.Write(jsonData)
}

These examples demonstrate the most common usage patterns for the H5P Go SDK. They show how to create content, handle errors properly, and integrate with larger applications.

Next Steps