Skip to content

feat(openapi): compile-time specs and scaffolding tools#624

Merged
pitabwire merged 8 commits intomainfrom
openapi-static
Feb 25, 2026
Merged

feat(openapi): compile-time specs and scaffolding tools#624
pitabwire merged 8 commits intomainfrom
openapi-static

Conversation

@pitabwire
Copy link
Owner

Summary

  • Add compile-time OpenAPI registry + HTTP endpoints
  • Add generator tool under tools/ to auto-generate specs and embed helper
  • Add blueprint merge semantics (additive by default) with tests
  • Document monorepo defaults (monolith + polylith) and /pkg convention

Testing

  • go test ./...

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @pitabwire, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the 'Frame' framework by integrating compile-time OpenAPI specification serving and introducing powerful scaffolding tools. The changes enable developers to automatically generate and embed OpenAPI documentation, ensuring API contracts are always up-to-date and served efficiently. Additionally, a new blueprint merging system provides flexible and safe configuration management, particularly beneficial for AI-assisted development, alongside tools for setting up monorepo projects with ease. These additions streamline development workflows and improve the maintainability and discoverability of services.

Highlights

  • Compile-time OpenAPI Integration: Introduced a new system for embedding OpenAPI specifications directly into Go binaries at compile time, ensuring deterministic and efficient serving of API documentation via dedicated HTTP endpoints.
  • OpenAPI Scaffolding Tool: Developed a frame-openapi command-line tool that automates the generation of OpenAPI specs from Protobuf definitions using buf and creates the necessary Go embedding code.
  • Blueprint Merge Semantics: Implemented a robust blueprint merging mechanism that is additive by default, allowing for explicit overrides and removals, which is designed to be safe for AI-driven code generation.
  • Monorepo Scaffolding Tool: Added a frame-init command-line tool to scaffold a monorepo structure, supporting both monolith and polylith architectures with per-service entry points and Dockerfiles.
  • Enhanced Documentation: Updated and added new documentation pages covering monorepo structure, blueprint principles, and the new OpenAPI integration, including AI-safe prompt patterns.
Changelog
  • blueprint/blueprint.go
    • Added core Go types for Blueprint, HTTPRoute, Plugin, and Queue, including JSON and YAML serialization tags.
  • blueprint/merge.go
    • Implemented a generic merge function for Blueprint structures, supporting additive, override, and remove operations for nested lists like HTTP routes, plugins, and queues.
  • blueprint/merge_test.go
    • Added comprehensive unit tests for the Blueprint merge logic, verifying additive behavior, explicit overrides, item removal, and service name mismatch error handling.
  • docs/ai-assistants.md
    • Updated the canonical directory structure to use /pkg instead of /internal for shared components.
    • Included /pkg/openapi in the recommended directory structure.
    • Added new prompt patterns for AI assistants related to OpenAPI generation and blueprint extension rules.
    • Introduced a new section on 'Blueprint Extension Rules (AI-Safe)' detailing additive, override, and remove semantics.
  • docs/blueprints.md
    • Added a new documentation page explaining Frame Blueprints, their core principles (additive merge, stable identifiers, explicit overrides, no implicit deletes), YAML format, extension examples, and merge rules.
  • docs/getting-started.md
    • Added a new section on the 'Default Repo Shape (Monorepo)' with an example directory structure.
    • Included a reference to the new monorepo.md document for detailed monorepo information.
  • docs/monorepo.md
    • Added a new documentation page detailing Frame's monorepo-first layout, supporting both monolith and polylith architectures.
    • Described the canonical monorepo layout, how to switch between modes, recommended conventions, and the frame-init scaffold tool with examples.
  • docs/openapi.md
    • Added a new documentation page for OpenAPI integration in Frame, outlining production goals, quick start instructions, served endpoints, compile-time guarantees, regeneration steps, custom base paths, CI integration, and troubleshooting tips.
  • mkdocs.yml
    • Updated the documentation navigation structure to include new entries for 'Monorepo', 'Blueprints', and 'OpenAPI' under the 'Concepts' and 'Runtime' sections, respectively.
  • openapi/embed.go
    • Added RegisterFromFS function to register OpenAPI specifications from an embed.FS directory, facilitating compile-time embedding.
  • openapi/embed_test.go
    • Added a test for RegisterFromFS to ensure that JSON files within an embedded file system are correctly registered as OpenAPI specs.
  • openapi/handler.go
    • Implemented ServeIndex and ServeSpec HTTP handlers to serve a JSON index of registered OpenAPI specs and individual spec content, respectively.
  • openapi/handler_test.go
    • Added unit tests for ServeIndex and ServeSpec handlers, verifying correct HTTP responses and content for OpenAPI index and individual spec requests.
  • openapi/registry.go
    • Defined Spec and Registry types to manage OpenAPI specifications, providing thread-safe methods for adding, retrieving, and listing specs.
  • options_openapi.go
    • Added WithOpenAPISpec to register a single OpenAPI spec.
    • Added WithOpenAPISpecsFromFS to register multiple OpenAPI specs from an embedded file system.
    • Added WithOpenAPIBasePath to customize the URL path for serving OpenAPI specs.
  • service.go
    • Imported strings and openapi packages.
    • Defined defaultOpenAPIBasePath constant.
    • Added openapiRegistry and openapiBasePath fields to the Service struct.
    • Initialized openapiBasePath to its default value in NewServiceWithContext.
    • Integrated registerOpenAPIRoutes into createAndConfigureMux to expose OpenAPI endpoints.
    • Implemented registerOpenAPIRoutes to conditionally register OpenAPI index and spec handlers if specs are present.
    • Implemented openAPIHandler to dispatch requests to ServeIndex or ServeSpec based on the request path.
  • tools/cmd/frame-init/main.go
    • Added a new command-line tool frame-init for scaffolding a monorepo project structure.
    • Implemented functions to create standard monorepo directories (apps, cmd, pkg, configs).
    • Provided functionality to generate a root Dockerfile and go.mod file.
    • Included logic to create service-specific layouts under apps/<service> with main.go and Dockerfile.
    • Added support for generating a monolith entry point (cmd/monolith/main.go) that combines multiple services.
  • tools/cmd/frame-openapi/main.go
    • Added a new command-line tool frame-openapi to automate OpenAPI spec generation and embedding.
    • Implemented functionality to run buf generate with a custom template to produce OpenAPI JSON files.
    • Provided logic to generate an embed.go file with //go:embed directives and an Option() helper for Frame services.
    • Included //go:generate directive generation for easy regeneration of specs.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link

There is a problem with the Gemini CLI PR review. Please check the action logs for details.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant new features: compile-time OpenAPI specification handling and scaffolding tools for new projects. The OpenAPI implementation is robust, using compile-time embedding for performance and predictability. The new blueprint merge semantics with additive defaults and explicit overrides are well-defined and tested. The documentation updates are comprehensive and clearly explain the new monorepo structure and tooling.

I've found a few issues in the new scaffolding tools. One is a high-severity bug in frame-init that generates broken code for the monolith entrypoint. Another is a medium-severity issue in frame-openapi that unnecessarily restricts path generation for go:generate directives. I've also pointed out some dead code in the blueprint merge logic.

Overall, this is a great addition to the framework. Addressing the issues in the tooling will make them much more reliable for developers.

Comment on lines +148 to +174
func writeMonolithEntry(root string, services []string) error {
path := filepath.Join(root, "cmd", "monolith", "main.go")
if exists(path) {
return nil
}
if err := ensureDir(filepath.Join(root, "cmd", "monolith")); err != nil {
return err
}

imports := []string{"\"log\"", "\"net/http\"", "\"github.com/pitabwire/frame\""}
for _, svc := range services {
imports = append(imports, fmt.Sprintf("\"%s/apps/%s/service\"", "your/module", svc))
}

var builders strings.Builder
builders.WriteString("package main\n\nimport (\n")
for _, imp := range imports {
builders.WriteString("\t" + imp + "\n")
}
builders.WriteString(")\n\nfunc main() {\n\tmux := http.NewServeMux()\n")
for _, svc := range services {
builders.WriteString(fmt.Sprintf("\t%s.RegisterRoutes(mux)\n", svc))
}
builders.WriteString("\tctx, svc := frame.NewService(\n\t\tframe.WithName(\"monolith\"),\n\t\tframe.WithHTTPHandler(mux),\n\t)\n\tif err := svc.Run(ctx, \":8080\"); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n")

return os.WriteFile(path, []byte(builders.String()), 0o644)
}
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved: module is now required when services are provided, monolith imports use proper aliases derived from service names, and the entrypoint is generated with those aliases.

Comment on lines +52 to +57
type mergeConfig[T any] struct {
key keyFunc[T]
replace replaceFunc[T]
override flagFunc[T]
remove flagFunc[T]
}
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved: removed unused mergeConfig struct and refactored merge helpers for clarity.

Comment on lines +139 to +148
func relPath(base, target string) (string, bool) {
rel, err := filepath.Rel(base, target)
if err != nil {
return "", false
}
if strings.HasPrefix(rel, "..") {
return "", false
}
return rel, true
}
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved: relPath now allows .. so go:generate works with sibling proto/pkg layouts.

@pitabwire pitabwire merged commit 5b45ece into main Feb 25, 2026
3 of 4 checks passed
@pitabwire pitabwire deleted the openapi-static branch February 25, 2026 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant