### Install and Run Goa Quick Start Example Source: https://github.com/goadesign/goa/blob/v3/README.md Installs Goa, sets up a new module, defines a simple 'hello' service, generates code, and runs the example server. This is a comprehensive guide to get started with Goa. ```bash # Install Goa go install goa.design/goa/v3/cmd/goa@latest # Create a new module mkdir hello && cd hello go mod init hello # Define a service in design/design.go mkdir design cat > design/design.go << EOF package design import . "goa.design/goa/v3/dsl" var _ = Service("hello", func() { Method("say_hello", func() { Payload(func() { Field(1, "name", String) Required("name") }) Result(String) HTTP(func() { GET("/hello/{name}") }) }) }) EOF # Generate the code goa gen hello/design goa example hello/design # Build and run go mod tidy go run cmd/hello/*.go --http-port 8000 # In another terminal curl http://localhost:8000/hello/world ``` -------------------------------- ### JSON-RPC Client Usage Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Example of how to instantiate and use a generated JSON-RPC client to call the 'Query' method. ```go client := api.NewClient("http", "localhost:8080", http.DefaultClient, goahttp.RequestEncoder, goahttp.ResponseDecoder, false) result, err := client.Query(ctx, &api.QueryPayload{SQL: "SELECT * FROM users"}) ``` -------------------------------- ### Example Interceptor Generation Data Source: https://github.com/goadesign/goa/blob/v3/codegen/service/interceptors.md These templates generate example interceptor implementations. The map structure includes interceptor details, service information, package name, and slices for server and client interceptors. ```go map[string]any{ "StructName": "ServiceName": "PkgName": "ServerInterceptors": "ClientInterceptors": } ``` -------------------------------- ### Install Goa Service Designer Skill for Cursor Source: https://github.com/goadesign/goa/blob/v3/skills/README.md Copy the goa-service-designer skill directory to the specified path for Cursor project skills. ```text .cursor/skills/goa-service-designer/SKILL.md ``` -------------------------------- ### Echo String SSE Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Tests the 'echo' action by returning the received string payload exactly as is. ```yaml # Example: echo_string_sse request: params: "hello world" expect: params: value: "hello world" # Exact echo ``` -------------------------------- ### Goa Project Build and Test Commands Source: https://github.com/goadesign/goa/blob/v3/AGENTS.md Essential commands for linting, testing, and installing the Goa CLI locally. Ensure you are in the project root directory. ```bash make lint # Run linters make test # Run tests cd cmd/goa && go install . # Install CLI locally ``` -------------------------------- ### HTTP Test Scenario Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Defines a single HTTP request-response test case. Use 'request' for input and 'expect' for the expected output. ```yaml - name: "http_test" method: "echo_string" transport: "http" request: # What we send params: "hello" id: 1 expect: # What we receive result: "hello" id: 1 ``` -------------------------------- ### Transform String SSE Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Tests the 'transform' action by converting a string payload to uppercase. ```yaml # Example: transform_string_sse request: params: "hello" expect: params: value: "HELLO" # Uppercase transformation ``` -------------------------------- ### Generate String SSE Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Tests the 'generate' action, which ignores the payload and returns a fixed sequence of values. ```yaml # Example: generate_string_sse request: params: "ignored" # Payload is ignored sequence: - expect: params: value: "generated-1" # Fixed sequence - expect: params: value: "generated-2" - expect: params: value: "generated-3" ``` -------------------------------- ### Server-Sent Events Frame Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md An example of how a Server-Sent Event is formatted on the wire. It includes the event type, an optional ID, and the JSON-RPC data payload, followed by a blank line to delimit the event. ```text event: metric id: 7 data: {"jsonrpc":"2.0","result":{"metric":"cpu","value":0.9},"id":"7"} ``` -------------------------------- ### Install Goa Service Designer Skill for Claude Source: https://github.com/goadesign/goa/blob/v3/skills/README.md Copy the goa-service-designer skill directory into your agent's skills directory for project-local or personal installation. ```bash mkdir -p .claude/skills cp -R path/to/goa/skills/goa-service-designer .claude/skills/ ``` ```bash mkdir -p ~/.claude/skills cp -R path/to/goa/skills/goa-service-designer ~/.claude/skills/ ``` -------------------------------- ### SSE Test Scenario Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Defines a test for Server-Sent Events (SSE). Use 'request' to initiate the connection and 'sequence' to define the expected stream of events. ```yaml - name: "sse_test" method: "stream_string_sse" transport: "sse" request: # Initiates SSE connection params: "test" id: "sse-1" sequence: # Stream of events we expect - type: "receive" expect: method: "stream_string_sse" # Notifications include method params: value: "Stream 1 of 4" # ... more events ``` -------------------------------- ### Stream Map Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Tests the 'stream' action with a map payload, where each key-value pair generates one notification. ```yaml # Example: Each key-value becomes a notification request: params: data: key1: "value1" key2: "value2" sequence: - expect: params: data: key: "key1" value: "value1" - expect: params: data: key: "key2" value: "value2" ``` -------------------------------- ### Stream Array Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Tests the 'stream' action with an array payload, where each item generates one notification. ```yaml # Example: Each item is processed request: params: items: ["first", "second"] sequence: - expect: params: items: ["Processing: first"] - expect: params: items: ["Processing: second"] ``` -------------------------------- ### Simple HTTP Test Scenario Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Define a basic HTTP JSON-RPC test case. This example sends a string and expects the same string back as a result. ```yaml - name: "my_echo_test" method: "echo_string" transport: "http" request: params: "hello world" id: 123 expect: result: "hello world" id: 123 ``` -------------------------------- ### JSON-RPC Request vs. Notification Examples Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Illustrates the difference between JSON-RPC requests (with ID) and notifications (without ID). Requests expect a response, while notifications do not. ```json {"jsonrpc": "2.0", "method": "process", "params": {"data": "hello"}, "id": "req-123"} // Server MUST send a response with matching ID ``` ```json {"jsonrpc": "2.0", "method": "log", "params": {"message": "user logged in"}} // Server MUST NOT send a response ``` -------------------------------- ### JSON-RPC Single Endpoint Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Demonstrates how multiple JSON-RPC methods are invoked through a single endpoint, identified by the 'method' field in the request payload. ```json {"jsonrpc": "2.0", "method": "add", "params": {"a": 5, "b": 3}, "id": 1} {"jsonrpc": "2.0", "method": "divide", "params": {"dividend": 10, "divisor": 2}, "id": 2} ``` -------------------------------- ### Regenerating Goa Code Source: https://github.com/goadesign/goa/blob/v3/skills/goa-service-designer/references/generated-code-and-implementation.md Use the project's wrapper command (e.g., `make gen`, `scripts/gen`) for regeneration. If no wrapper exists, use `goa gen `. Never use `goa gen ./design` as Goa expects a Go import path. `goa example` is for first-time scaffolding. ```bash goa gen ``` -------------------------------- ### Install Goa Service Designer Skill for Codex Source: https://github.com/goadesign/goa/blob/v3/skills/README.md Copy the goa-service-designer skill directory into your agent's skills directory for repository-scoped Codex skills. ```bash mkdir -p .agents/skills cp -R path/to/goa/skills/goa-service-designer .agents/skills/ ``` -------------------------------- ### Stream String Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Tests the 'stream' action with a string payload, where payload length determines the number of messages. ```yaml # Example: 5 characters = 5 messages request: params: "12345" # Length 5 sequence: - expect: params: value: "Stream 1 of 5" # ... continues to "Stream 5 of 5" ``` -------------------------------- ### Configure JSON-RPC Service Endpoint Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Enables JSON-RPC for a service and defines the shared endpoint using HTTP POST or WebSocket GET. ```go Service("myservice", func() { Description("A service exposed via JSON-RPC") // Define the JSON-RPC endpoint JSONRPC(func() { POST("/jsonrpc") // For HTTP and SSE // OR GET("/ws") // For WebSocket }) // Define error mappings for all methods Error("unauthorized", func() { Description("Unauthorized access") }) JSONRPC(func() { Response("unauthorized", func() { Code(-32000) // Map to JSON-RPC error code }) }) }) ``` -------------------------------- ### WebSocket Test Scenario Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Defines a bidirectional WebSocket test. Use 'sequence' to manage the series of messages sent and received, including connection and closure. ```yaml - name: "websocket_test" method: "echo_string_ws" transport: "websocket" sequence: # Series of sends and receives - type: "connect" # Optional: explicit connection - type: "send" data: method: "echo_string_ws" params: id: "ws-1" value: "hello" id: "ws-1" - type: "receive" expect: id: "ws-1" result: value: "hello" - type: "close" # Close the connection ``` -------------------------------- ### JSON-RPC Batch Request Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Demonstrates sending multiple JSON-RPC requests within a single HTTP call for efficient processing. The server returns an array of responses corresponding to each request. ```json [ {"jsonrpc": "2.0", "method": "add", "params": {"a": 1, "b": 2}, "id": 1}, {"jsonrpc": "2.0", "method": "multiply", "params": {"a": 3, "b": 4}, "id": 2}, {"jsonrpc": "2.0", "method": "divide", "params": {"dividend": 10, "divisor": 2}, "id": 3} ] ``` -------------------------------- ### JSON-RPC Batch Response Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Illustrates the structure of responses when multiple JSON-RPC requests are processed in a batch. Each response corresponds to its original request ID. ```json [ {"jsonrpc": "2.0", "result": 3, "id": 1}, {"jsonrpc": "2.0", "result": 12, "id": 2}, {"jsonrpc": "2.0", "result": 5, "id": 3} ] ``` -------------------------------- ### Configuring API Version Selection Strategy Source: https://github.com/goadesign/goa/wiki/Versioning-APIs Shows how to configure the API version selection strategy using a combination of header and query parameter lookups. This allows flexibility in how clients specify the desired API version. ```go service.SelectVersion(goa.CombineSelectVersionFunc( goa.HeaderSelectVersionFunc("X-API-Version"), goa.QuerySelectVersionFunc("api_version")) ) ``` -------------------------------- ### Mounting a Versioned Controller in Goa Source: https://github.com/goadesign/goa/wiki/Versioning-APIs Demonstrates how to obtain a version-specific ServeMux and mount a controller's handler for a particular API version. Ensure the mux for the specified version exists. ```go mux := service.ServeMux().Version("1.0") if mux == nil { panic("no mux for version 1.0") } // ... mux.Handle("POST", "/cellar/accounts", ctrl.HandleFunc("Create", h)) ``` -------------------------------- ### HTTP GET Endpoint Mapping Source: https://github.com/goadesign/goa/blob/v3/skills/goa-service-designer/references/transport-errors-interceptors.md Defines an HTTP GET endpoint for retrieving items associated with an account. It maps a path parameter 'account_id', accepts a 'limit' query parameter, and specifies success and not-found responses. ```go HTTP(func() { GET("/accounts/{account_id}/items") Param("limit") Response(StatusOK) Response("not_found", StatusNotFound) }) ``` -------------------------------- ### HandleStream Method Implementation Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/ARCHITECTURE.md The entry point for all WebSocket communication where developers implement application-specific streaming logic. It can listen to channels, timers, or events, and interact with the stream interface to receive requests or send responses. ```go func (s *serviceImpl) HandleStream(ctx context.Context, stream ServiceName.Stream) error { // User implements their streaming strategy here. // Can listen to channels, timers, events, etc. // Can call stream.Recv() to process incoming JSON-RPC requests. // Can call stream.SendMethodName() to send responses or notifications. } ``` -------------------------------- ### Stream Object Example Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Tests the 'stream' action with an object payload, where 'field2' controls the number of notifications. ```yaml # Example: field2 controls count request: params: field1: "test" field2: 2 # Will send 2 notifications field3: false sequence: - expect: params: field1: "test-1" field2: 1 field3: false - expect: params: field1: "test-2" field2: 2 field3: true # Last item is true ``` -------------------------------- ### Content Negotiation with HTTP and SSE Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Demonstrates how to combine HTTP and Server-Sent Events (SSE) in a single service using automatic content negotiation based on the Accept header. ```APIDOC ## Hybrid Service with Content Negotiation ### Description This service supports both standard JSON-RPC over HTTP and Server-Sent Events (SSE) by automatically negotiating the content type based on the `Accept` header. - `Accept: application/json` routes to the standard HTTP handler using the `Result`. - `Accept: text/event-stream` routes to the SSE handler using the `StreamingResult`. ### Methods #### status ##### Description Provides the health status of the service. ##### Result - **healthy** (Boolean) - Indicates if the service is healthy. ##### JSONRPC ```go Method("status", func() { Result(func() { Attribute("healthy", Boolean) Required("healthy") }) JSONRPC(func() {}) }) ``` #### monitor ##### Description Streams real-time updates using Server-Sent Events. ##### StreamingResult - **event** (String) - The type of event. - **data** (Any) - The event data. ##### JSONRPC ```go Method("monitor", func() { StreamingResult(func() { Attribute("event", String) Attribute("data", Any) }) JSONRPC(func() { ServerSentEvents(func() { SSEEventType("update") }) }) }) ``` #### flexible ##### Description Handles requests with content negotiation, returning either a simple HTTP result or an SSE stream based on the `Accept` header. ##### Payload - **resource** (String) - The resource to process. ##### Result (for HTTP) - **data** (String) - The processed data. ##### StreamingResult (for SSE) - **chunk** (String) - A chunk of the streamed data. - **progress** (Int) - The progress of the operation. ##### JSONRPC ```go Method("flexible", func() { Payload(func() { Attribute("resource", String) Required("resource") }) Result(func() { Attribute("data", String) Required("data") }) StreamingResult(func() { Attribute("chunk", String) Attribute("progress", Int) }) JSONRPC(func() { ServerSentEvents(func() { SSEEventType("progress") }) }) }) ``` ``` -------------------------------- ### Golden File Path Configuration Source: https://github.com/goadesign/goa/blob/v3/codegen/testutil/README.md Demonstrates how to configure the base path for golden files using NewGoldenFile. An empty path defaults to 'testdata/golden'. Assert functions use paths exactly as provided. ```go // Uses "testdata/golden" as base path gf := testutil.NewGoldenFile(t, "") gf.StringContent(code).Path("output.golden").CompareContent() // Creates: testdata/golden/output.golden // Uses custom base path gf := testutil.NewGoldenFile(t, "testdata/custom") gf.StringContent(code).Path("output.golden").CompareContent() // Creates: testdata/custom/output.golden // Assert functions use paths exactly as provided testutil.AssertString(t, "testdata/golden/output.golden", code) // Creates: testdata/golden/output.golden ``` -------------------------------- ### Method Naming Convention: Generate String Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Illustrates the 'generate' action with a string type, producing a predefined generated string regardless of input. ```markdown | **generate** | string | (ignored) | `"generated-string"` | ``` -------------------------------- ### Implement JSON-RPC Report and Streaming Handlers Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Implement service methods for handling synchronous JSON reports and streaming Server-Sent Events (SSE) based on the defined DSL. ```go // Called for Accept: application/json func (s *svc) Report(ctx context.Context, p *ReportPayload) (*ReportResult, error) { summary, count := generateReport(p.Query) return &ReportResult{Summary: summary, Count: count}, nil } // Called for Accept: text/event-stream func (s *svc) ReportStream(ctx context.Context, p *ReportPayload, stream ReportServerStream) error { rows := queryRows(p.Query) for i, row := range rows { err := stream.Send(ctx, &ReportStreamingResult{ Row: row, Progress: float64(i) / float64(len(rows)), }) if err != nil { return err } } return nil } ``` -------------------------------- ### Define API Version with DSL Source: https://github.com/goadesign/goa/wiki/Versioning-APIs Use the `Version` DSL function to declare an API version and configure its properties. Only fields that differ from the main `API` DSL definition need to be specified. ```go var _ = Version("2.0", func() { Title("This is the winecellar API 2.0") // Version title used in documentation Description("description") // Version description used in documentation TermsOfService("terms") // Each version can define its own terms Contact(func() { Name("contact name") Email("contact email") URL("contact URL") }) License(func() { Name("license name") URL("license URL") }) Docs(func() { Description("doc description") URL("doc URL") }) Host("goa.design") // Version hostname Scheme("http") // Supported HTTP methods BasePath("/base/:param") // Common base path to all API actions for this version BaseParams(func() { Param("param") }) ResponseTemplate("static", func() { Description("description") Status(404) MediaType("application/json") }) Trait("Authenticated", func() { Headers(func() { Header("header") Required("header") }) }) ``` -------------------------------- ### Implement JSON-RPC Calculator Service Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Provides the concrete implementation for the calculator service, handling the add and divide methods. Includes error handling for division by zero. ```go // calc.go package calcapi import ( "context" calc "calculator/gen/calc" ) type calcService struct{} func NewCalc() calc.Service { return &calcService{} } func (s *calcService) Add(ctx context.Context, p *calc.AddPayload) (float64, error) { return p.A + p.B, nil } func (s *calcService) Divide(ctx context.Context, p *calc.DividePayload) (float64, error) { if p.Divisor == 0 { return 0, calc.MakeDivisionByZero("cannot divide by zero") } return p.Dividend / p.Divisor, nil } ``` -------------------------------- ### Method Naming Convention: Echo String Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Illustrates the 'echo' action with a string type, where the output is identical to the input. ```markdown | **echo** | string | `"hello"` | `"hello"` | ``` -------------------------------- ### Method Naming Convention: Generate Object Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Illustrates the 'generate' action with an object type, producing a predefined object with specific fields and values. ```markdown | **generate** | object | (ignored) | `{field1: "generated-value1", field2: 42, field3: true}` | ``` -------------------------------- ### Method Naming Convention: Generate Array Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Illustrates the 'generate' action with an array type, producing a predefined array of strings. ```markdown | **generate** | array | (ignored) | `{items: ["item1", "item2", "item3"]}` | ``` -------------------------------- ### Goa JSON-RPC Code Generation Steps Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/ARCHITECTURE.md Illustrates the three-step process for composing JSON-RPC specific code on top of the base HTTP transport code generation. It shows how to add imports, modify existing sections, and append new JSON-RPC specific sections. ```go // Step 1: Generate base HTTP code f := httpcodegen.ServerEncodeDecodeFile(genpkg, svc, data) // Step 2: Modify sections before final code generation for _, s := range f.SectionTemplates { // Add JSON-RPC imports if s.Name == "source-header" { codegen.AddImport(s, codegen.GoaImport("jsonrpc")) } // Modify signatures for JSON-RPC context if s.Name == "request-decoder" { s.Source = strings.Replace(s.Source, httpRequestDecoderTemplate, jsonrpcRequestDecoderTemplate, 1) } // Namespace sections to avoid conflicts s.Name = "jsonrpc-" + s.Name } // Step 3: Add JSON-RPC specific sections sections = append(sections, &codegen.SectionTemplate{ Name: "jsonrpc-server-handler-init", Source: jsonrpcTemplates.Read(serverHandlerInitT), Data: e }) ``` -------------------------------- ### Hybrid Service with Content Negotiation Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Define a service that supports both standard JSON-RPC and Server-Sent Events (SSE) using content negotiation. The server automatically selects the appropriate handler based on the `Accept` header. ```go Service("hybrid", func() { JSONRPC(func() { POST("/api") }) // Standard HTTP method Method("status", func() { Result(func() { Attribute("healthy", Boolean) Required("healthy") }) JSONRPC(func() {}) // Implicitly JSONRPC }) // SSE streaming method Method("monitor", func() { StreamingResult(func() { Attribute("event", String) Attribute("data", Any) }) JSONRPC(func() { ServerSentEvents(func() { SSEEventType("update") }) }) }) // Mixed results with content negotiation Method("flexible", func() { Payload(func() { Attribute("resource", String) Required("resource") }) // Return simple result for HTTP Result(func() { Attribute("data", String) Required("data") }) // Return stream for SSE StreamingResult(func() { Attribute("chunk", String) Attribute("progress", Int) }) JSONRPC(func() { ServerSentEvents(func() { SSEEventType("progress") }) }) }) }) ``` -------------------------------- ### Define Primitive Alias for Reusable Constraints Source: https://github.com/goadesign/goa/blob/v3/skills/goa-service-designer/references/modeling-and-validation.md Use primitive aliases for reusable constraints on primitive values like IDs or constrained codes. This centralizes validation, examples, and domain meaning. ```go var AccountID = Type("AccountID", String, func() { Description("Stable account identifier.") Format(FormatUUID) Example("2551dfde-513e-4840-b1be-9bb78d5930e9") }) Payload(func() { Field(1, "accountId", AccountID, "Account to query.") Required("accountId") }) ``` -------------------------------- ### Method Naming Convention: Echo Object Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Illustrates the 'echo' action with an object type, where the output is identical to the input. ```markdown | **echo** | object | `{field1: "x", field2: 1, field3: true}` | Same as input | ``` -------------------------------- ### Define WebSocket Service with JSON-RPC Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Defines a chat service with methods for client-to-server notifications, server-to-client notifications, and bidirectional echo using JSON-RPC over WebSockets. The GET("/ws") endpoint is used for the WebSocket upgrade. ```go Service("chat", func() { JSONRPC(func() { GET("/ws") // WebSocket upgrade }) // Client-to-server notifications Method("send", func() { StreamingPayload(func() { Attribute("message", String) Required("message") }) JSONRPC(func() {}) }) // Server-to-client notifications Method("broadcast", func() { StreamingResult(func() { Attribute("from", String) Attribute("message", String) Required("from", "message") }) JSONRPC(func() {}) }) // Bidirectional request-response Method("echo", func() { StreamingPayload(func() { ID("msg_id", String) Attribute("text", String) Required("msg_id", "text") }) StreamingResult(func() { ID("msg_id", String) Attribute("echo", String) Required("msg_id", "echo") }) JSONRPC(func() {}) }) }) ``` -------------------------------- ### Define Nested Map and Array Type in Goa Source: https://github.com/goadesign/goa/blob/v3/grpc/docs/FAQ.md When proto3 syntax does not support nested maps and arrays, Goa wraps the inner types into user types with a single 'field' attribute. This example shows how a nested map of string to an array of booleans is defined. ```go Type("MyType", func() { Field(3, "nested", MapOf(Int, MapOf(String, ArrayOf(Bool)))) }) ``` -------------------------------- ### Run All Integration Tests Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Execute all integration tests in parallel with verbose output. This command bypasses the test cache. ```bash go test -count=1 -v ./... ``` -------------------------------- ### Generated Protobuf for Any Type Echo Method Source: https://github.com/goadesign/goa/blob/v3/grpc/docs/FAQ.md This shows the protobuf definitions generated for an 'echo' method using the `Any` type, which maps to `google.protobuf.Value`. ```proto import "google/protobuf/struct.proto"; message EchoRequest { optional google.protobuf.Value data = 1; } message EchoResponse { optional google.protobuf.Value data = 1; } ``` -------------------------------- ### Advanced Golden File Comparison with Fluent API Source: https://github.com/goadesign/goa/blob/v3/codegen/testutil/README.md Employ the fluent API for more control over the comparison process. This allows chaining methods for path specification and content comparison. ```go func TestWithFluentAPI(t *testing.T) { gf := testutil.NewGoldenFile(t, "testdata/golden") code := generateCode() gf.StringContent(code). Path("service.go.golden"). CompareContent() } ``` -------------------------------- ### Method Naming Convention: Echo Array Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Illustrates the 'echo' action with an array type, where the output is identical to the input. ```markdown | **echo** | array | `{items: ["a", "b"]}` | `{items: ["a", "b"]}` | ``` -------------------------------- ### Method Naming Convention: Generate Map Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Illustrates the 'generate' action with a map type, producing a predefined map with generated data. ```markdown | **generate** | map | (ignored) | `{data: {generated: true, count: 3, status: "ok"}}` | ``` -------------------------------- ### Run a Single Integration Test by Name Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Execute a specific integration test scenario by its name from the YAML file. The format is TestJSONRPC/. ```bash go test -count=1 -v -run "TestJSONRPC/echo_string_request" ./... ``` -------------------------------- ### Enable gRPC Stream Compatibility Mode Source: https://github.com/goadesign/goa/blob/v3/grpc/docs/FAQ.md To support clients using the pre-envelope stream protocol, set the `grpc:stream:compat` meta on the method, service, or API. This allows generated servers to accept both protocols. ```go Meta("grpc:stream:compat", "v1") ``` -------------------------------- ### Method Naming Convention: Echo Map Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Illustrates the 'echo' action with a map type, where the output is identical to the input. ```markdown | **echo** | map | `{data: {k: "v"}}` | `{data: {k: "v"}}` | ``` -------------------------------- ### Apply Boundary Validation with Defaults and Constraints Source: https://github.com/goadesign/goa/blob/v3/skills/goa-service-designer/references/modeling-and-validation.md Define payload fields with validation rules, including defaults, minimum, and maximum constraints. Ensure required fields are marked appropriately. ```go Payload(func() { Field(1, "accountId", AccountID, "Account identifier.") Field(2, "limit", Int, "Maximum number of items.", func() { Default(50) Minimum(1) Maximum(100) }) Required("accountId") }) ``` -------------------------------- ### WebSocket Bidirectional Streaming Scenario Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Illustrates a WebSocket test scenario involving a client subscription and subsequent server broadcasts. It uses a `sequence` to define the order of `send` and `receive` steps, including expected results and unsolicited messages. ```yaml scenarios: - name: "broadcast_websocket_interaction" method: "broadcast_string" transport: "websocket" sequence: # 1. Client sends a subscription request - type: "send" data: jsonrpc: "2.0" method: "broadcast_string" # Method to call on the server params: { "channel": "news" } id: "sub-1" # 2. Client expects a confirmation response - type: "receive" expect: jsonrpc: "2.0" id: "sub-1" result: { "status": "subscribed", "channel": "news" } # 3. Client waits to receive an unsolicited broadcast from the server - type: "receive" expect: jsonrpc: "2.0" method: "broadcast" # Note: This is a server-initiated method, not a response params: { "message": "Server update!" } ``` -------------------------------- ### Define Calculator Service with JSON-RPC Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Defines a calculator service with add and divide methods, enabling JSON-RPC support at the /rpc endpoint. Includes custom error handling for division by zero. ```go // design/design.go package design import . "goa.design/goa/v3/dsl" var _ = API("calculator", func() { Title("Calculator Service") Description("A simple calculator exposed via JSON-RPC") }) var _ = Service("calc", func() { Description("The calc service performs basic arithmetic") // Enable JSON-RPC for this service at /rpc endpoint JSONRPC(func() { POST("/rpc") }) // Define an add method Method("add", func() { Description("Add two numbers") Payload(func() { Attribute("a", Float64, "First operand") Attribute("b", Float64, "Second operand") Required("a", "b") }) Result(Float64) // Expose this method via JSON-RPC JSONRPC(func() {}) }) // Define a divide method with error handling Method("divide", func() { Description("Divide two numbers") Payload(func() { Field(1, "dividend", Float64, "The dividend") Field(2, "divisor", Float64, "The divisor") Required("dividend", "divisor") }) Result(Float64) Error("division_by_zero") JSONRPC(func() { Response("division_by_zero", func() { Code(-32001) // Custom error code }) }) }) }) ``` -------------------------------- ### Method Naming Convention: Transform String Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/integration_tests/README.md Illustrates the 'transform' action with a string type, converting the input string to uppercase. ```markdown | **transform** | string | `"hello"` | `"HELLO"` | ``` -------------------------------- ### Goa Codegen Issue Reproduction Protocol Source: https://github.com/goadesign/goa/blob/v3/AGENTS.md Steps to set up a reproducible environment for Goa code generation issues. This involves creating a specific directory structure and modifying Go module paths. ```bash go mod init goa gen /design go mod tidy go mod edit -replace goa.design/goa/v3=$HOME/src/goa goa gen /design again with local goa Optional: goa example /design ``` -------------------------------- ### Snapshotting Design and Generated Files Before Regeneration Source: https://github.com/goadesign/goa/blob/v3/skills/goa-service-designer/references/generated-code-and-implementation.md Before running generation in a dirty worktree, snapshot the relevant design and generated files using git diff. Adjust paths to match your project layout. ```bash git diff -- design services gen ``` -------------------------------- ### Method Configuration Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Configures individual methods for JSON-RPC exposure, including payload, result, and error mappings. ```APIDOC ## Method Configuration Each method needs its own `JSONRPC()` block to be exposed: ```go Method("process", func() { Description("Process data") Payload(func() { Attribute("data", String, "Data to process") Attribute("priority", Int, "Processing priority") Required("data") }) Result(func() { Attribute("output", String, "Processed output") Attribute("duration", Int, "Processing time in ms") Required("output", "duration") }) // Enable JSON-RPC for this method JSONRPC(func() { // Method-specific error mappings (optional) Response("invalid_data", func() { Code(-32002) }) }) }) ``` ``` -------------------------------- ### Goa API Design Workflow Source: https://github.com/goadesign/goa/blob/v3/README.md Illustrates the typical workflow for designing an API with Goa, from design to implementation and evolution. ```text ┌─────────────┐ ┌──────────────┐ ┌─────────────────────┐ │ Design API │────>│ Generate Code│────>│ Implement Business │ │ using DSL │ │ & Docs │ │ Logic │ └─────────────┘ └──────────────┘ └─────────────────────┘ ``` -------------------------------- ### Implement WebSocket Service Handler Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Provides the server-side implementation for a chat WebSocket service. It handles connection lifecycle, message reception, and dispatching to specific method handlers like 'Send' and 'Echo'. ```go type chatSvc struct { connections map[string]chat.BroadcastServerStream mu sync.RWMutex } func (s *chatSvc) HandleStream(ctx context.Context, stream chat.Stream) error { // Register connection connID := generateConnID() s.mu.Lock() s.connections[connID] = stream.(chat.BroadcastServerStream) s.mu.Unlock() defer func() { s.mu.Lock() delete(s.connections, connID) s.mu.Unlock() stream.Close() }() // Handle incoming messages for { _, err := stream.Recv(ctx) if err != nil { return err } // Messages are automatically dispatched to method handlers } } func (s *chatSvc) Send(ctx context.Context, p *chat.SendPayload) error { // Broadcast to all connections s.mu.RLock() defer s.mu.RUnlock() for _, conn := range s.connections { conn.SendNotification(ctx, &chat.BroadcastResult{ From: "user", Message: p.Message, }) } return nil } func (s *chatSvc) Echo(ctx context.Context, p *chat.EchoPayload, stream chat.EchoServerStream) error { return stream.SendResponse(ctx, &chat.EchoResult{ MsgID: p.MsgID, Echo: "Echo: " + p.Text, }) } ``` -------------------------------- ### Basic Golden File Test in Go Source: https://github.com/goadesign/goa/blob/v3/codegen/testutil/README.md Use AssertString for simple comparisons of generated code against a golden file. Ensure the golden file exists in the specified path. ```go func TestCodeGen(t *testing.T) { // Generate your code code := generateSomeCode() // Compare with golden file testutil.AssertString(t, "testdata/golden/expected.golden", code) } ``` -------------------------------- ### JSON-RPC Service Definition Source: https://github.com/goadesign/goa/blob/v3/README.md Shows how to define a service and method for JSON-RPC communication within Goa's DSL. This is an alternative to the default HTTP transport. ```go var _ = Service("hello" , func() { JSONRPC(func() { Path("/jsonrpc") }) Method("say_hello", func() { Payload(func() { Field(1, "name", String) Required("name") }) Result(String) JSONRPC(func() {}) }) } ``` -------------------------------- ### Testing Multiple Generated Files with Batch Source: https://github.com/goadesign/goa/blob/v3/codegen/testutil/README.md Utilize the Batch API to test multiple related generated files simultaneously. This ensures consistency across all generated outputs. ```go func TestMultipleFiles(t *testing.T) { batch := testutil.NewBatch(t) batch.AddString("server.go.golden", generateServer()). AddString("client.go.golden", generateClient()). AddString("types.go.golden", generateTypes()). Compare() } ``` -------------------------------- ### Implement SSE Server Stream Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Implement the server-side logic for the SSE stream. Use the provided `stream` interface to send events periodically or based on conditions. Handle context cancellation to gracefully stop streaming. ```go func (s *monitorSvc) Watch(ctx context.Context, p *monitor.WatchPayload, stream monitor.WatchServerStream) error { ticker := time.NewTicker(1 * time.Second) defer ticker.Stop() for { select { case <-ctx.Done(): return nil case <-ticker.C: for _, metric := range p.Metrics { err := stream.Send(ctx, &monitor.WatchResult{ Metric: metric, Value: getMetricValue(metric), Timestamp: time.Now().Format(time.RFC3339), }) if err != nil { return err } } } } } ``` -------------------------------- ### Configure HTTP Transport Mapping Source: https://github.com/goadesign/goa/blob/v3/skills/goa-service-designer/references/troubleshooting.md Map design elements to HTTP transport details. Ensure path tokens map to payload fields and specify parameter mappings, headers, and responses. ```go HTTP(func() { GET("/accounts/{account_id}/items") Param("accountId:account_id") Param("limit") Response(StatusOK) Response("not_found", StatusNotFound) }) ``` -------------------------------- ### Send Method Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Allows clients to send messages to the server, which are then broadcast to all connected clients. ```APIDOC ## Send Method ### Description Sends a message from the client to the server. The server broadcasts this message to all connected clients. ### Method JSONRPC ### Endpoint /ws ### Parameters #### Request Body - **message** (string) - Required - The message content to send. ``` -------------------------------- ### Configure JSON-RPC Method Exposure Source: https://github.com/goadesign/goa/blob/v3/jsonrpc/README.md Exposes a method for JSON-RPC, defining its payload, result structure, and optional method-specific error mappings. ```go Method("process", func() { Description("Process data") Payload(func() { Attribute("data", String, "Data to process") Attribute("priority", Int, "Processing priority") Required("data") }) Result(func() { Attribute("output", String, "Processed output") Attribute("duration", Int, "Processing time in ms") Required("output", "duration") }) // Enable JSON-RPC for this method JSONRPC(func() { // Method-specific error mappings (optional) Response("invalid_data", func() { Code(-32002) }) }) }) ```