Go 1.22+ is required. Use generics where they improve code clarity or reduce duplication (e.g., ListResponse[T], SingleResponse[T]).
The use of gofmt and goimports is mandatory. Run these tools before every commit to ensure consistency.
While there is no hard line length limit, prefer wrapping around 100-120 characters to maintain readability. Use tabs for indentation as per standard Go conventions.
- Packages: Use lowercase, single-word names (e.g.,
api,config,iostreams). - Exported symbols: Use PascalCase for types and functions.
- Unexported symbols: Use camelCase for types and functions.
- Constants: Use PascalCase for exported constants and camelCase for unexported ones.
- Acronyms: Capitalize acronyms fully (e.g.,
HTTPClient,APIURL,SSLCert). - Files: Use snake_case for filenames (e.g.,
types_route.go,list_test.go). - Test functions: Follow the pattern
Test<Function>_<Scenario>(e.g.,TestRouteList_EmptyResponse).
Always return errors and avoid ignoring them with _. Never use panic() for expected error conditions.
Error messages should be lowercase and without trailing punctuation. Wrap errors with context using the %w verb:
return fmt.Errorf("failed to list routes: %w", err)Use the APIError type from pkg/api/types.go for API-specific errors:
type APIError struct {
StatusCode int `json:"-"`
ErrorMsg string `json:"message"`
}- IDs: Use
stringfor resource IDs, not pointers. - Required fields: Use value types like
stringorint. - Optional fields: Use pointer types such as
*stringor*int. This ensures that JSONomitemptytags work correctly by distinguishing between a zero value and a missing value. - JSON tags: Match the exact API7 EE API field names, which typically use snake_case.
Example:
type Route struct {
ID string `json:"id"`
Name string `json:"name"` // Required in API7 EE
URI *string `json:"uri,omitempty"`
Methods []string `json:"methods,omitempty"`
}Group imports into three blocks separated by blank lines:
- Standard library packages
- Third-party packages
- Internal project packages (
github.com/api7/a7/...)
The pkg/ directory contains code that can be imported by external consumers. Use the internal/ directory for code that should not be accessible outside this module. Each package should have a single, clear responsibility. Avoid circular dependencies.
- Avoid global variables, except for version information.
- Do not use
init()functions, unless they are necessary for cobra command registration. - Avoid
interface{}oranywhen a concrete type can be used. - Do not use unchecked type assertions.
- Never call
os.Exit()directly outside ofcmd/a7/main.go. - Use
IOStreamsfor all output instead offmt.Println.
Prefer the standard library over external packages whenever possible. The following external dependencies are approved:
github.com/spf13/cobra(command framework)github.com/spf13/viper(configuration)github.com/stretchr/testify(test assertions)gopkg.in/yaml.v3(YAML processing)github.com/olekukonez/tablewriter(table rendering)
Adding a new dependency requires explicit justification in the pull request description.
Always use the Config interface via the Factory. Do not access viper directly in commands.
- Use
cfg.Token()instead ofcfg.APIKey(). - Use
cfg.GatewayGroup()for scoping. - Use
cfg.TLSSkipVerify()andcfg.CACert()for HTTPS transport configuration.