Repository navigation
feat(notification): generate event contracts from TypeSpec #5303
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
6b9de00
feat(notification): generate event contracts from TypeSpec
gergely-kurucz-konghq 3e751ed
test(notification): cover event contract validation and emitted files
gergely-kurucz-konghq 6f576e8
refactor(notification): embed event contract JSON Schemas as bytes
gergely-kurucz-konghq bbf6f78
refactor(notification): move the event type package to notification/v4
gergely-kurucz-konghq 594dffc
refactor(notification): rename the event type files to event.go
gergely-kurucz-konghq 6552d16
refactor(notification): emit event types and schemas into events.gen.go
gergely-kurucz-konghq File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| openapi: 3.0.0 | ||
| info: | ||
| title: Billing.NotificationEvents | ||
| description: Notification Event contracts owned by the billing domain. | ||
| version: 0.0.0 | ||
| tags: [] | ||
| paths: {} | ||
| components: | ||
| schemas: | ||
| BillingInvoiceCreatedV1Payload: | ||
| type: object | ||
| required: | ||
| - invoice_id | ||
| - customer_id | ||
| - status | ||
| - currency | ||
| - total | ||
| properties: | ||
| invoice_id: | ||
| allOf: | ||
| - $ref: "#/components/schemas/ULID" | ||
| description: Invoice that was created. | ||
| customer_id: | ||
| allOf: | ||
| - $ref: "#/components/schemas/ULID" | ||
| description: Customer the invoice belongs to. | ||
| status: | ||
| type: string | ||
| description: Invoice status at creation time. | ||
| currency: | ||
| allOf: | ||
| - $ref: "#/components/schemas/CurrencyCode" | ||
| description: Invoice currency. | ||
| total: | ||
| allOf: | ||
| - $ref: "#/components/schemas/Numeric" | ||
| description: Invoice total at creation time. | ||
| additionalProperties: false | ||
| description: |- | ||
| Payload of `v1.billing.invoice.created`. | ||
|
|
||
| The payload identifies the invoice and carries its state at creation time; | ||
| consumers fetch the full invoice through the API when they need it. | ||
| CurrencyCode: | ||
| type: string | ||
| minLength: 3 | ||
| maxLength: 3 | ||
| pattern: ^[A-Z]{3}$ | ||
| description: |- | ||
| Three-letter [ISO4217](https://www.iso.org/iso-4217-currency-codes.html) | ||
| currency code. Custom three-letter currency codes are also supported for | ||
| convenience. | ||
| example: USD | ||
| Numeric: | ||
| type: string | ||
| pattern: ^\-?[0-9]+(\.[0-9]+)?$ | ||
| description: Numeric represents an arbitrary precision number. | ||
| ULID: | ||
| type: string | ||
| pattern: ^[0-7][0-9A-HJKMNP-TV-Z]{25}$ | ||
| description: ULID (Universally Unique Lexicographically Sortable Identifier). | ||
| title: ULID | ||
| example: 01G65Z755AFWAKHE12NY0CQ9FH |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| openapi: 3.0.0 | ||
| info: | ||
| title: Entitlements.NotificationEvents | ||
| description: Notification Event contracts owned by the entitlements domain. | ||
| version: 0.0.0 | ||
| tags: [] | ||
| paths: {} | ||
| components: | ||
| schemas: | ||
| EntitlementBalanceThreshold: | ||
| type: object | ||
| required: | ||
| - type | ||
| - value | ||
| properties: | ||
| type: | ||
| allOf: | ||
| - $ref: "#/components/schemas/EntitlementBalanceThresholdType" | ||
| description: Condition kind of the threshold. | ||
| value: | ||
| type: number | ||
| format: double | ||
| description: Threshold value, interpreted according to the threshold type. | ||
| additionalProperties: false | ||
| description: A single entitlement balance threshold. | ||
| EntitlementBalanceThresholdTriggeredV1Payload: | ||
| type: object | ||
| required: | ||
| - customer_id | ||
| - entitlement_id | ||
| - feature_key | ||
| - current_balance | ||
| - threshold | ||
| properties: | ||
| customer_id: | ||
| allOf: | ||
| - $ref: "#/components/schemas/ULID" | ||
| description: Customer owning the entitlement. | ||
| entitlement_id: | ||
| allOf: | ||
| - $ref: "#/components/schemas/ULID" | ||
| description: Entitlement whose balance crossed the threshold. | ||
| feature_key: | ||
| allOf: | ||
| - $ref: "#/components/schemas/ResourceKey" | ||
| description: Feature of the entitlement. | ||
| current_balance: | ||
| type: number | ||
| format: double | ||
| description: Balance at evaluation time. | ||
| threshold: | ||
| allOf: | ||
| - $ref: "#/components/schemas/EntitlementBalanceThreshold" | ||
| description: Threshold that was crossed. | ||
| additionalProperties: false | ||
| description: Payload of `v1.entitlement.balance_threshold.triggered`. | ||
| EntitlementBalanceThresholdTriggeredV1RuleConfig: | ||
| type: object | ||
| required: | ||
| - thresholds | ||
| properties: | ||
| thresholds: | ||
| type: array | ||
| items: | ||
| $ref: "#/components/schemas/EntitlementBalanceThreshold" | ||
| minItems: 1 | ||
| description: Thresholds evaluated against the entitlement balance. | ||
| features: | ||
| type: array | ||
| items: | ||
| $ref: "#/components/schemas/ResourceKey" | ||
| description: Feature keys the Rule is limited to. All features when omitted. | ||
| additionalProperties: false | ||
| description: Rule configuration of `v1.entitlement.balance_threshold.triggered`. | ||
| EntitlementBalanceThresholdType: | ||
| type: string | ||
| enum: | ||
| - balance_at_or_below | ||
| - usage_percentage_at_or_above | ||
| description: Condition kind of an entitlement balance threshold. | ||
| ResourceKey: | ||
| type: string | ||
| minLength: 1 | ||
| maxLength: 64 | ||
| pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$ | ||
| description: A key is a unique string that is used to identify a resource. | ||
| title: Resource Key | ||
| example: resource_key | ||
| ULID: | ||
| type: string | ||
| pattern: ^[0-7][0-9A-HJKMNP-TV-Z]{25}$ | ||
| description: ULID (Universally Unique Lexicographically Sortable Identifier). | ||
| title: ULID | ||
| example: 01G65Z755AFWAKHE12NY0CQ9FH |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
api/spec/packages/aip/oapi-codegen.notification-events.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json | ||
| # Shared oapi-codegen configuration of every domain notificationevents package. | ||
| # The generated go:generate directive in each package (generate.gen.go) passes | ||
| # the package name (-package) and the output file (-o), so neither is set here. | ||
| generate: | ||
| models: true | ||
| compatibility: | ||
| disable-required-readonly-as-pointer: true | ||
| always-prefix-enum-values: true | ||
| output-options: | ||
| nullable-type: true | ||
| skip-prune: true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 84 additions & 0 deletions
84
api/spec/packages/aip/scripts/generate-notification-events.mjs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| // Generates the per-domain Notification Event artifacts and copies them into | ||
| // the Go module. | ||
| // | ||
| // Run after `tsp compile --config tspconfig.notification-events.yaml`, which | ||
| // emits the JSON Schemas, the generated Go files and manifest.json. For every @goPackage | ||
| // namespace in the manifest this script: | ||
| // 1. compiles a generated entry point that makes the namespace an OpenAPI | ||
| // service, producing the events-only OpenAPI document of its types; | ||
| // 2. copies that document to its committed location under api/, and the | ||
| // emitted generate.gen.go, events.gen.go and JSON Schemas into the Go | ||
| // package directory. `go generate` then runs oapi-codegen through the | ||
| // directive in generate.gen.go, like every other oapi-codegen target. | ||
| import { execFileSync } from 'node:child_process' | ||
| import { cpSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs' | ||
| import { dirname, join, relative, resolve } from 'node:path' | ||
| import { fileURLToPath } from 'node:url' | ||
|
|
||
| const pkgRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..') | ||
| const repoRoot = resolve(pkgRoot, '../../../..') | ||
| const out = join(pkgRoot, 'output/notification-events') | ||
| const manifest = JSON.parse( | ||
| readFileSync(join(out, '_go/manifest.json'), 'utf8'), | ||
| ) | ||
|
|
||
| for (const entry of manifest) { | ||
| const entryDir = join(out, 'entries') | ||
| const entryFile = join(entryDir, `${entry.dir.replaceAll('/', '_')}.tsp`) | ||
| const openapiDir = join(out, 'openapi', entry.dir) | ||
| mkdirSync(entryDir, { recursive: true }) | ||
| writeFileSync( | ||
| entryFile, | ||
| [ | ||
| `import "${relative(entryDir, join(pkgRoot, 'src/notification-events.tsp'))}";`, | ||
| '', | ||
| `@@TypeSpec.service(${entry.namespace}, #{ title: "${entry.namespace}" });`, | ||
| '', | ||
| ].join('\n'), | ||
| ) | ||
| execFileSync( | ||
| 'tsp', | ||
| [ | ||
| 'compile', | ||
| '--config', | ||
| join(pkgRoot, 'tspconfig.notification-events-openapi.yaml'), | ||
| entryFile, | ||
| '--option', | ||
| `@typespec/openapi3.emitter-output-dir=${openapiDir}`, | ||
| ], | ||
| { cwd: pkgRoot, stdio: 'inherit' }, | ||
| ) | ||
| // Same post-processing as v3: oapi-codegen and kin-openapi need | ||
| // additionalProperties: false instead of the emitter's { not: {} }. | ||
| execFileSync( | ||
| 'node', | ||
| [ | ||
| join(pkgRoot, 'scripts/seal-object-schemas.mjs'), | ||
| join(openapiDir, 'openapi.yaml'), | ||
| ], | ||
| { | ||
| stdio: 'inherit', | ||
| }, | ||
| ) | ||
|
|
||
| const goDir = join(repoRoot, entry.dir) | ||
| mkdirSync(goDir, { recursive: true }) | ||
| mkdirSync(dirname(join(repoRoot, entry.spec)), { recursive: true }) | ||
| cpSync(join(openapiDir, 'openapi.yaml'), join(repoRoot, entry.spec)) | ||
| cpSync( | ||
| join(out, '_go', entry.dir, 'generate.gen.go'), | ||
| join(goDir, 'generate.gen.go'), | ||
| ) | ||
| rmSync(join(goDir, 'events.gen.go'), { force: true }) | ||
| rmSync(join(goDir, 'schemas'), { recursive: true, force: true }) | ||
| if (entry.schemas.length > 0) { | ||
| cpSync( | ||
| join(out, '_go', entry.dir, 'events.gen.go'), | ||
| join(goDir, 'events.gen.go'), | ||
| ) | ||
| mkdirSync(join(goDir, 'schemas')) | ||
| for (const { source, target } of entry.schemas) { | ||
| cpSync(join(out, 'jsonschema', source), join(goDir, 'schemas', target)) | ||
| } | ||
| } | ||
| } |
1 change: 1 addition & 0 deletions
1
api/spec/packages/aip/src/billing/notification-events/index.tsp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| import "./invoice.tsp"; |
48 changes: 48 additions & 0 deletions
48
api/spec/packages/aip/src/billing/notification-events/invoice.tsp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| import "@typespec/json-schema"; | ||
| import "@openmeter/typespec-notification-events"; | ||
| import "../../shared/index.tsp"; | ||
|
|
||
| using TypeSpec.JsonSchema; | ||
| using NotificationCodegen; | ||
|
|
||
| /** | ||
| * Notification Event contracts owned by the billing domain. | ||
| */ | ||
| namespace Billing.NotificationEvents; | ||
|
|
||
| /** | ||
| * Payload of `v1.billing.invoice.created`. | ||
| * | ||
| * The payload identifies the invoice and carries its state at creation time; | ||
| * consumers fetch the full invoice through the API when they need it. | ||
| */ | ||
| @jsonSchema | ||
| @id("v1.billing.invoice.created.payload") | ||
| @eventType("v1.billing.invoice.created") | ||
| @friendlyName("BillingInvoiceCreatedV1Payload") | ||
| model InvoiceCreatedV1Payload { | ||
| /** | ||
| * Invoice that was created. | ||
| */ | ||
| invoice_id: Shared.ULID; | ||
|
|
||
| /** | ||
| * Customer the invoice belongs to. | ||
| */ | ||
| customer_id: Shared.ULID; | ||
|
|
||
| /** | ||
| * Invoice status at creation time. | ||
| */ | ||
| status: string; | ||
|
|
||
| /** | ||
| * Invoice currency. | ||
| */ | ||
| currency: Shared.CurrencyCode; | ||
|
|
||
| /** | ||
| * Invoice total at creation time. | ||
| */ | ||
| total: Shared.Numeric; | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.