Skip to content

Commit

Permalink
feat: currencies endpoint (#2126)
Browse files Browse the repository at this point in the history
  • Loading branch information
turip authored Jan 21, 2025
1 parent d206126 commit 0512c10
Show file tree
Hide file tree
Showing 12 changed files with 927 additions and 645 deletions.
1,335 changes: 690 additions & 645 deletions api/api.gen.go

Large diffs are not rendered by default.

77 changes: 77 additions & 0 deletions api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ info:
OpenMeter is a cloud native usage metering service.
The OpenMeter API allows you to ingest events, query meter usage, and manage resources.
tags:
- name: Static Data
- name: Meters
description: Meters specify how to aggregate events for billing and analytics purposes. Meters can be configured with multiple aggregation methods and groupings. Multiple meters can be created for the same event type, enabling flexible metering scenarios.
- name: Events
Expand Down Expand Up @@ -5709,6 +5710,59 @@ paths:
$ref: '#/components/schemas/UnexpectedProblemResponse'
tags:
- Portal
/api/v1/static/currencies:
get:
operationId: listCurrencies
summary: List supported currencies
description: List all supported currencies.
parameters: []
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Currency'
'400':
description: The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).
content:
application/problem+json:
schema:
$ref: '#/components/schemas/BadRequestProblemResponse'
'401':
description: The request has not been applied because it lacks valid authentication credentials for the target resource.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/UnauthorizedProblemResponse'
'403':
description: The server understood the request but refuses to authorize it.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ForbiddenProblemResponse'
'500':
description: The server encountered an unexpected condition that prevented it from fulfilling the request.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/InternalServerErrorProblemResponse'
'503':
description: The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ServiceUnavailableProblemResponse'
default:
description: An unexpected error response.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/UnexpectedProblemResponse'
tags:
- Static Data
/api/v1/stripe/checkout/sessions:
post:
operationId: createStripeCheckoutSession
Expand Down Expand Up @@ -8700,6 +8754,29 @@ components:
allOf:
- $ref: '#/components/schemas/InvoiceGenericDocumentRef'
description: CreditNoteOriginalInvoiceRef is used to reference the original invoice that a credit note is based on.
Currency:
type: object
required:
- code
- name
- symbol
- subunits
properties:
code:
allOf:
- $ref: '#/components/schemas/CurrencyCode'
description: The currency ISO code.
name:
type: string
description: The currency name.
symbol:
type: string
description: The currency symbol.
subunits:
type: integer
format: uint32
description: Subunit of the currency.
description: Currency describes a currency supported by OpenMeter.
CurrencyCode:
type: string
minLength: 3
Expand Down
6 changes: 6 additions & 0 deletions api/spec/src/cloud/main.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,12 @@ namespace OpenMeterCloud.ProductCatalog {
interface Subscriptions extends OpenMeter.ProductCatalog.Subscriptions {}
}

namespace OpenMeterCloud.Static {
@route("/api/v1/static")
@tag("Static Data")
interface Currencies extends OpenMeter.Static.Currencies {}
}

/**
* A meter is a configuration that defines how to match and aggregate events.
*/
Expand Down
1 change: 1 addition & 0 deletions api/spec/src/main.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import "./notification";
import "./entitlements";
import "./billing";
import "./productcatalog";
import "./static";

using TypeSpec.Http;
using TypeSpec.Rest;
Expand Down
30 changes: 30 additions & 0 deletions api/spec/src/static/currencies.tsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace OpenMeter.Static;

using TypeSpec.Http;
using TypeSpec.OpenAPI;

/**
* Currency describes a currency supported by OpenMeter.
*/
@friendlyName("Currency")
model Currency {
/**
* The currency ISO code.
*/
code: CurrencyCode;

/**
* The currency name.
*/
name: string;

/**
* The currency symbol.
*/
symbol: string;

/**
* Subunit of the currency.
*/
subunits: uint32;
}
11 changes: 11 additions & 0 deletions api/spec/src/static/main.tsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import "@typespec/http";
import "@typespec/openapi";
import "@typespec/openapi3";

import "..";

// Package Contents
import "./currencies.tsp";
import "./routes.tsp";

namespace OpenMeter.Static;
19 changes: 19 additions & 0 deletions api/spec/src/static/routes.tsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import "../rest.tsp";

namespace OpenMeter.Static;

using TypeSpec.Http;
using TypeSpec.OpenAPI;

@route("/api/v1/static")
@tag("Static Data")
interface Currencies {
/**
* List all supported currencies.
*/
@get
@operationId("listCurrencies")
@route("/currencies")
@summary("List supported currencies")
listCurrencies(): Currency[] | OpenMeter.CommonErrors;
}
6 changes: 6 additions & 0 deletions openmeter/server/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
plansubscription "github.com/openmeterio/openmeter/openmeter/productcatalog/subscription"
subscriptionhttpdriver "github.com/openmeterio/openmeter/openmeter/productcatalog/subscription/http"
"github.com/openmeterio/openmeter/openmeter/server/authenticator"
statichttpdriver "github.com/openmeterio/openmeter/openmeter/static/httpdriver"
"github.com/openmeterio/openmeter/openmeter/streaming"
"github.com/openmeterio/openmeter/openmeter/subscription"
"github.com/openmeterio/openmeter/pkg/errorsx"
Expand Down Expand Up @@ -182,6 +183,7 @@ type Router struct {
entitlementHandler entitlementdriver.EntitlementHandler
meteredEntitlementHandler entitlementdriver.MeteredEntitlementHandler
notificationHandler notificationhttpdriver.Handler
staticHandler statichttpdriver.Handler
}

// Make sure we conform to ServerInterface
Expand Down Expand Up @@ -236,6 +238,10 @@ func NewRouter(config Config) (*Router, error) {
httptransport.WithErrorHandler(config.ErrorHandler),
)

router.staticHandler = statichttpdriver.New(
httptransport.WithErrorHandler(config.ErrorHandler),
)

// Customer
router.customerHandler = customerhttpdriver.New(
staticNamespaceDecoder,
Expand Down
9 changes: 9 additions & 0 deletions openmeter/server/router/static.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package router

import "net/http"

// List supported currencies
// (GET /api/v1/static/currencies)
func (a *Router) ListCurrencies(w http.ResponseWriter, r *http.Request) {
a.staticHandler.ListCurrencies().ServeHTTP(w, r)
}
45 changes: 45 additions & 0 deletions openmeter/static/httpdriver/currencies.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package httpdriver

import (
"context"
"net/http"

"github.com/invopop/gobl/currency"
"github.com/samber/lo"

"github.com/openmeterio/openmeter/api"
"github.com/openmeterio/openmeter/pkg/framework/commonhttp"
"github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"
)

type (
ListCurrenciesRequest struct{}
ListCurrenciesResponse []api.Currency
ListCurrenciesHandler httptransport.Handler[ListCurrenciesRequest, ListCurrenciesResponse]
)

func (h *handler) ListCurrencies() ListCurrenciesHandler {
return httptransport.NewHandler(
func(ctx context.Context, r *http.Request) (ListCurrenciesRequest, error) {
return ListCurrenciesRequest{}, nil
},
func(ctx context.Context, request ListCurrenciesRequest) (ListCurrenciesResponse, error) {
defs := currency.Definitions()

return lo.Map(defs, func(def *currency.Def, _ int) api.Currency {
return api.Currency{
Code: api.CurrencyCode(def.ISOCode),
Name: def.Name,
Symbol: def.Symbol,
Subunits: def.Subunits,
}
}), nil
},
commonhttp.JSONResponseEncoderWithStatus[ListCurrenciesResponse](http.StatusOK),
httptransport.AppendOptions(
h.options,
httptransport.WithOperationName("listCurrencies"),
httptransport.WithErrorEncoder(errorEncoder()),
)...,
)
}
17 changes: 17 additions & 0 deletions openmeter/static/httpdriver/driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package httpdriver

import "github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"

type Handler interface {
ListCurrencies() ListCurrenciesHandler
}

type handler struct {
options []httptransport.HandlerOption
}

func New(options ...httptransport.HandlerOption) Handler {
return &handler{
options: options,
}
}
16 changes: 16 additions & 0 deletions openmeter/static/httpdriver/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package httpdriver

import (
"context"
"net/http"

"github.com/openmeterio/openmeter/pkg/framework/commonhttp"
"github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"
"github.com/openmeterio/openmeter/pkg/models"
)

func errorEncoder() httptransport.ErrorEncoder {
return func(ctx context.Context, err error, w http.ResponseWriter, r *http.Request) bool {
return commonhttp.HandleErrorIfTypeMatches[*models.GenericUserError](ctx, http.StatusBadRequest, err, w)
}
}

0 comments on commit 0512c10

Please sign in to comment.