183 lines
10 KiB
Markdown
183 lines
10 KiB
Markdown
# example.com/managed
|
|
|
|
This checked-in example uses a relative local framework replacement (`../..`).
|
|
Run `go mod tidy && go run .` here. No external database or cloud account is required.
|
|
The Go-only error catalog is `internal/apierrors/catalog.go`, registered by svc.
|
|
The generated main and handlers are unmodified. Built-in endpoint switches and
|
|
paths are configured in etc/config.yaml under server.endpoints. Health replies
|
|
use the project envelope by default; responseMode: raw opts out. Readiness
|
|
failures stay HTTP 503, independently of business error status policies.
|
|
|
|
Dependencies can call svc.RequestShutdown(err); the generated entry drains
|
|
requests, closes resources and retains the failure for a nonzero exit.
|
|
Try:
|
|
|
|
```sh
|
|
curl -i 'http://127.0.0.1:8080/check?kind=fixed'
|
|
curl -i 'http://127.0.0.1:8080/check?kind=params'
|
|
curl -i 'http://127.0.0.1:8080/missing'
|
|
curl -i -H 'X-Signature: valid' --data-binary ' {"hello":1} ' http://127.0.0.1:8080/callback
|
|
curl -i -F 'file=hello' http://127.0.0.1:8080/upload
|
|
curl -OJ http://127.0.0.1:8080/download
|
|
```
|
|
|
|
The upload demonstration caps requests at 2048 bytes, so use a small test file;
|
|
large input is intentionally rejected with HTTP 413. Replace the demonstration
|
|
`X-Signature` check with the actual provider's signature algorithm and secret.
|
|
From the framework root, check generated files with:
|
|
`go run ./cmd/go-omni api generate --dir examples/managedService --check`.
|
|
|
|
Contract changes produce REVIEW notices for affected Logic methods and DTO fields.
|
|
Definite Logic signature problems produce ERROR diagnostics with a file/line and
|
|
the required signature. Regeneration preserves business code; `--check` continues
|
|
to fail on unresolved signature errors after generation. Run `go test ./...` too,
|
|
especially for project type aliases, build tags and changes inside method bodies.
|
|
|
|
|
|
This project is generated from an editable API contract. Business code uses
|
|
standard context.Context; generated HTTP handlers use Omni's transport-neutral httpx.
|
|
main.go and HTTP composition are continuously generator-owned.
|
|
|
|
## Run
|
|
|
|
```sh
|
|
go mod tidy
|
|
go run .
|
|
```
|
|
|
|
GET /health/live and /health/ready check the running service. GET /openapi.json
|
|
serves the same document as docs/openapi.json. Bind address defaults to localhost.
|
|
Set GO_OMNI_TRANSPORT=native to select the native transport without changing services.
|
|
The greeting starter works immediately; other new operation stubs return 501 until
|
|
their business logic is implemented. Authentication hooks also fail closed with 501.
|
|
|
|
## Develop
|
|
|
|
1. Edit api/managed.api and its relative imports.
|
|
2. Run the same go-omni CLI version as the framework dependency:
|
|
|
|
```sh
|
|
go-omni api validate
|
|
go-omni api inspect
|
|
go-omni api generate --dry-run
|
|
go-omni api generate
|
|
go-omni api generate --check
|
|
go-omni api export > openapi.json
|
|
go test ./...
|
|
```
|
|
|
|
Commands inside a generated project discover the recorded API entry automatically.
|
|
--dry-run previews create/update/remove actions without writing files.
|
|
The --check command is read-only and suitable for CI. It fails on stale or missing
|
|
generated files and missing business scaffolds. go.mod, configuration, Logic,
|
|
Repository, svc, middleware hook bodies and API files are created once and then
|
|
preserved byte for byte. main.go, Gen.go files and OpenAPI are owned
|
|
by the generator; manual edits cause a conflict instead of being overwritten.
|
|
Commit .goOmni/apiManifest.json alongside the generated files. Do not edit it.
|
|
Avoid editing files while generation is running; api.lock serializes generators.
|
|
|
|
Routes and types that disappear are removed from generated output. Handwritten
|
|
business files remain: remove/adapt obsolete implementations explicitly if an
|
|
API change makes their old types or signatures fail to compile. Every regeneration
|
|
must be followed by go test ./... . Do not delete service files to change contracts.
|
|
|
|
## Layout
|
|
|
|
```text
|
|
api/ # editable contract and imported types
|
|
main.go # GENERATED startup, lifecycle and route registration
|
|
etc/config.yaml # lowerCamelCase configuration
|
|
internal/config/ # defaults -> file -> environment
|
|
internal/svc/ # dependency initialization and cleanup
|
|
internal/types/typesGen.go # generated request/response types
|
|
internal/apierrors/errorsGen.go # generated fresh error constructors, when declared
|
|
internal/handler/<group>/ # generated binding and Logic adapters
|
|
internal/logic/<group>/ # developer-owned business operations
|
|
internal/repository/<group>/ # developer-owned persistence contracts
|
|
internal/middleware/ # named hooks and generated registry
|
|
docs/openapi.json # generated OpenAPI 3.0.3
|
|
.goOmni/apiManifest.json # ownership and content hashes
|
|
```
|
|
|
|
The API response type describes business data. Declare response Name (...) and
|
|
select the App default with @app(defaultResponse: Name) in the entry API.
|
|
@server(response: Name) and @response Name override it for groups/routes;
|
|
@response raw returns the business JSON directly. Without a template, the default
|
|
envelope includes code, message, data and requestId. Generated routes and OpenAPI
|
|
use the same contract. 404/405 and ordinary App routes use the declared App default.
|
|
No template is selected by declaration/import order. Without @app, existing framework
|
|
response defaults apply. An explicit API App default takes precedence over response
|
|
options in svc, keeping generated routes and OpenAPI consistent.
|
|
Handlers reject nil successful responses. Body DTOs use application/json and have a 1 MiB limit by default.
|
|
Use @body(maxBytes: ...) for route limits. @body(mode: raw|multipart; maxBytes: ...)
|
|
adds a *httpx.Body argument to Logic, without handwritten handlers. Raw is the exact
|
|
limited request stream; Parts supports sequential multipart reading with no temp files.
|
|
@produces "application/octet-stream" (or another concrete media type) generates a
|
|
Logic result of *httpx.Stream; the handler closes Content and streams it unwrapped.
|
|
Signature verification and storage policy belong to Logic/middleware. A consumed
|
|
request stream cannot be reread automatically; use one reader owner or explicitly
|
|
bounded buffering. Stream reads respect configured server timeouts. Multipart parts
|
|
are not DTO form fields: form tags remain URL query parameters. The optional manual
|
|
handler/custom binder hooks are preserved, and are needed only for custom protocols.
|
|
|
|
Fields require exactly one source tag: json, path, form (URL query only), header.
|
|
All are required by presence unless optional, omitempty or default is specified.
|
|
Zero and false are valid present values; binding:"required" rejects scalar zero.
|
|
Use *T with optional when business logic needs to distinguish missing from zero.
|
|
Pointers may carry null; non-pointer null is rejected. Unknown/duplicate JSON
|
|
fields and duplicate scalar query/header values are rejected. Arrays in the query
|
|
use repeated keys. Enum/range/default and nested fields share the documentation
|
|
and binding compiler. Responses are expected to honor their declared constraints;
|
|
they are not validated on every response. Do not return nil slices/maps for a
|
|
non-nullable collection (initialize empty collections instead).
|
|
|
|
Go-owned errors can be registered once through svc.ServiceContext.AppOptions with
|
|
omni.WithErrors(projecterrors.Catalog()). Generated routes inherit them unless they
|
|
declare an independent catalog. Do not repeat Go-owned errors in the API contract.
|
|
Alternatively, declare public business errors in error (...) and reference them with @errors.
|
|
Use internal/apierrors constructors to share status, code and message with OpenAPI.
|
|
Auth declarations connect a bearer/header/cookie scheme to a real named middleware.
|
|
The selected auth runs first; @auth none removes inherited declarative auth.
|
|
Validation policy remains in the middleware implementation. Public messages must
|
|
not contain secrets; error causes may be included in server logs.
|
|
|
|
svc.New receives the loaded Config and borrowed Logger. Add dependencies there,
|
|
then immediately register each cleanup with OnClose. A later initialization failure
|
|
runs registered cleanups in reverse order. Close is idempotent. GlobalMiddleware
|
|
provides global hooks; Middlewares supplies named API hooks. AppOptions is evaluated
|
|
once before route registration; logging is configured earlier through Config.
|
|
The generated main runs HTTP draining before closing svc resources, then the logger.
|
|
Do not close borrowed resources or attach duplicate cleanup hooks to App. The startup
|
|
context cancels on signals; long-lived clients/workers that requests depend on need
|
|
their own lifetime, canceled by OnClose after HTTP draining.
|
|
|
|
Named middleware is composed in declaration order (first is outermost). Implement
|
|
the generated hooks or replace entries in svc; never bypass an auth
|
|
hook merely to make the server start. Middleware names do not imply a JWT policy.
|
|
|
|
This CLI supports a documented go-zero-style subset, not all goctl features.
|
|
Database tables and repositories cannot be inferred from an HTTP contract. Add
|
|
business repositories through svc. Database and storage options are
|
|
composed at creation; the original profile is retained on regeneration.
|
|
|
|
## Infrastructure
|
|
|
|
Selected database: none; storage: none; logging: stderr/json.
|
|
MySQL uses database/sql through deps.DB, including InTx and a readiness probe.
|
|
Set GO_OMNI_DB_DSN; pool settings live in etc/config.yaml and GO_OMNI_DB_*.
|
|
No tables are invented or migrated automatically from request/response DTOs.
|
|
The none/memory selection opens no database; implement repositories per business.
|
|
|
|
With storage enabled, services receive deps.Files, Uploads, Downloads and
|
|
UploadLinks capability interfaces. Local signed GET/HEAD/PUT uses /storage/object;
|
|
set GO_OMNI_STORAGE_SIGNING_KEY (32+ bytes) and GO_OMNI_STORAGE_PUBLIC_URL.
|
|
Cloud credentials use GO_OMNI_STORAGE_ACCESS_KEY/SECRET_KEY; set bucket and endpoint
|
|
or R2 accountId as appropriate. Signed URLs grant temporary access: authenticate
|
|
and authorize before issuing them. No public upload-link route is added.
|
|
Storage failures during startup close an already-open database; Close is idempotent.
|
|
|
|
Database/storage/logging selection is recorded in .goOmni/apiManifest.json.
|
|
Changing selection through generation flags is rejected on an existing project;
|
|
edit your owned configuration and initialization explicitly, or generate a fresh
|
|
project for comparison. New routes still regenerate without repeating these flags.
|