Skip to content

Commit

Permalink
feat(customer): crud api (#1544)
Browse files Browse the repository at this point in the history
Co-authored-by: Alex Goth <[email protected]>
  • Loading branch information
hekike and GAlexIHU authored Sep 24, 2024
1 parent 6434abd commit add50af
Show file tree
Hide file tree
Showing 49 changed files with 4,751 additions and 2,545 deletions.
985 changes: 684 additions & 301 deletions api/api.gen.go

Large diffs are not rendered by default.

1,738 changes: 1,344 additions & 394 deletions api/client/go/client.gen.go

Large diffs are not rendered by default.

451 changes: 451 additions & 0 deletions api/openapi.yaml

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions api/spec/src/billing.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ model TaxConfig {
/**
* A tax provider.
*/
@friendlyName("Tax Provider")
@friendlyName("TaxProvider")
union TaxProvider {
/**
* OpenMeter test billing provider.
Expand All @@ -40,7 +40,7 @@ union TaxProvider {
/**
* A invoicing provider.
*/
@friendlyName("Invoicing Provider")
@friendlyName("InvoicingProvider")
union InvoicingProvider {
/**
* OpenMeter test billing provider.
Expand All @@ -60,7 +60,7 @@ union InvoicingProvider {
/**
* A payment provider.
*/
@friendlyName("Payment Provider")
@friendlyName("PaymentProvider")
union PaymentProvider {
/**
* OpenMeter test billing provider.
Expand Down
128 changes: 99 additions & 29 deletions api/spec/src/customer.tsp
Original file line number Diff line number Diff line change
@@ -1,22 +1,110 @@
import "@typespec/http";
import "@typespec/rest";
import "@typespec/openapi3";

import "./errors.tsp";
import "./billing.tsp";
import "./pagination.tsp";
import "./types.tsp";

using TypeSpec.Http;
using TypeSpec.OpenAPI;

namespace OpenMeter;

/**
* Customer API.
*/
@route("/api/v1/customers")
@tag("Customers")
interface Customers {
/**
* Create a new customer.
*/
@post
@operationId("createCustomer")
create(@body customer: Customer): Customer | CommonErrors;

/**
* List customers.
*/
@get
@operationId("listCustomers")
list(...ListCustomersParams): Paginated<Customer>[] | CommonErrors;

/**
* Get a customer by ID or key.
*/
@get
@route("/{customerIdOrKey}")
@operationId("getCustomer")
get(@path customerIdOrKey: CustomerIdentifier): Customer | NotFoundError | CommonErrors;

/**
* Update a customer by ID or key.
*/
@put
@route("/{customerIdOrKey}")
@operationId("updateCustomer")
update(@path customerIdOrKey: CustomerIdentifier, @body customer: Customer): Customer | NotFoundError | CommonErrors;

/**
* Delete a customer by ID or key.
*/
@delete
@route("/{customerIdOrKey}")
@operationId("deleteCustomer")
delete(@path customerIdOrKey: CustomerIdentifier): Customer | NotFoundError | CommonErrors;
}

/**
* Query params for listing customers.
*/
@friendlyName("queryCustomerList")
model ListCustomersParams extends PaginatedQuery {
/**
* Include deleted customers.
*/
@query
includeDeleted?: boolean = false;
}

/**
* A unique customer identifier.
*/
@extension("x-go-type", "string")
@friendlyName("CustomerIdentifier")
union CustomerIdentifier {
ULID,
Key,
}

/**
* A customer object.
*/
@friendlyName("Customer")
model Customer extends Resource {
@example(#{
id: "01G65Z755AFWAKHE12NY0CQ9FH",
name: "ACME Inc.",
usageAttribution: #{ subjectKeys: #["my_subject_key"] },
external: #{ stripeCustomerId: "cus_xxxxxxxxxxxxxx" },
createdAt: DateTime.fromISO("2024-01-01T01:01:01.001Z"),
updatedAt: DateTime.fromISO("2024-01-01T01:01:01.001Z"),
})
model Customer {
...Resource;

/**
* A unique identifier for the customer.
* Timezone of the customer.
*
* @TODO: use a Timezone type to validate the value
*/
@visibility("read")
@example("01G65Z755AFWAKHE12NY0CQ9FH")
@summary("ID")
id: ULID;
@summary("Timezone")
timezone?: string;

// Mapping to attribute metered usage to the customer
/**
* Mapping to attribute metered usage to the customer
*/
@summary("Usage Attribution")
usageAttribution: CustomerUsageAttribution;

Expand All @@ -40,24 +128,6 @@ model Customer extends Resource {
@summary("Billing Address")
billingAddress?: Address;

/**
* The tax provider for the customer.
*/
@summary("Tax Provider")
taxProvider?: TaxProvider;

/**
* The invoicing provider for the customer.
*/
@summary("Invoicing Provider")
invoicingProvider?: InvoicingProvider;

/**
* The payment provider for the customer.
*/
@summary("Payment Provider")
paymentProvider?: PaymentProvider;

/**
* External mappings for the customer.
*/
Expand All @@ -70,22 +140,22 @@ model Customer extends Resource {
* One customer can have multiple subjects,
* but one subject can only belong to one customer.
*/
@friendlyName("Usage Attribution")
@friendlyName("CustomerUsageAttribution")
model CustomerUsageAttribution {
/**
* The subjects that are attributed to the customer.
* @TODO allow multiple subjects
*/
@summary("Subjects")
@summary("SubjectKeys")
@minItems(1)
@maxItems(1)
subjects: Key[];
subjectKeys: string[];
}

/**
* External mappings for the customer.
*/
@friendlyName("External Mapping")
@friendlyName("CustomerExternalMapping")
model CustomerExternalMapping {
/**
* The Stripe customer ID.
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 @@ -9,6 +9,7 @@ import "./errors.tsp";
import "./types.tsp";

import "./query.tsp";
import "./customer.tsp";
import "./events.tsp";
import "./meters.tsp";
import "./portal.tsp";
Expand Down
2 changes: 1 addition & 1 deletion api/spec/src/plan.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ enum PlanStatus {
* Plans provide a template for subscriptions.
*/
@friendlyName("Plan")
model Plan extends Resource {
model Plan extends UniqueResource {
/**
* Version of the plan. Incremented when the plan is updated.
*/
Expand Down
29 changes: 24 additions & 5 deletions api/spec/src/types.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,31 @@ scalar DateTime extends utcDateTime;
scalar Money extends string;

/**
* Represents common fields of resources.
* Represents a resource with a unique key.
*/
@friendlyName("Resource")
model Resource {
@friendlyName("UniqueResource")
model UniqueResource {
...Resource;

/**
* A semi-unique identifier for the resource.
*/
@summary("Key")
key: Key;
}

/**
* Represents common fields of resources.
*/
@friendlyName("Resource")
model Resource {
/**
* A unique identifier for the resource.
*/
@visibility("read")
@example("01G65Z755AFWAKHE12NY0CQ9FH")
@summary("ID")
id: ULID;

/**
* Human-readable name for the resource. Between 1 and 256 characters.
Expand All @@ -74,7 +90,7 @@ model Resource {
* Additional metadata for the resource.
*/
@summary("Metadata")
metadata?: Metadata;
metadata?: Metadata; // FIXME: linter error for: = #{};

...ResourceTimestamps;
}
Expand All @@ -89,20 +105,23 @@ model ResourceTimestamps {
*/
@summary("Creation Time")
@visibility("read")
@example(DateTime.fromISO("2024-01-01T01:01:01.001Z"))
createdAt: DateTime;

/**
* Timestamp of when the resource was last updated.
*/
@summary("Last Update Time")
@visibility("read")
@example(DateTime.fromISO("2024-01-01T01:01:01.001Z"))
updatedAt: DateTime;

/**
* Timestamp of when the resource was permanently deleted.
*/
@summary("Deletion Time")
@visibility("read")
@example(DateTime.fromISO("2024-01-01T01:01:01.001Z"))
deletedAt?: DateTime;
}

Expand Down Expand Up @@ -200,7 +219,7 @@ scalar CountryCode extends string;
*/
@friendlyName("Address")
model Address {
country: CountryCode;
country?: CountryCode;
postalCode?: string;
state?: string;
city?: string;
Expand Down
6 changes: 3 additions & 3 deletions api/spec/tspconfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ output-dir: '{base-dir}'
options:
'@typespec/openapi3':
emitter-output-dir: '{output-dir}/output'
linter:
extends:
- '@openmeter/api-spec/all'
# linter:
# extends:
# - '@openmeter/api-spec/all'
27 changes: 27 additions & 0 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import (
"go.opentelemetry.io/otel/trace"

"github.com/openmeterio/openmeter/config"
"github.com/openmeterio/openmeter/openmeter/customer"
customerrepository "github.com/openmeterio/openmeter/openmeter/customer/repository"
"github.com/openmeterio/openmeter/openmeter/debug"
"github.com/openmeterio/openmeter/openmeter/ingest"
"github.com/openmeterio/openmeter/openmeter/ingest/ingestadapter"
Expand Down Expand Up @@ -369,6 +371,30 @@ func main() {
})
}

// Initialize Customer
var customerService customer.CustomerService

if entClient != nil {
var customerRepo customer.Repository
customerRepo, err = customerrepository.New(customerrepository.Config{
Client: entClient,
Logger: logger.WithGroup("customer.postgres"),
})
if err != nil {
logger.Error("failed to initialize customer repository", "error", err)
os.Exit(1)
}

customerService, err = customer.NewService(customer.ServiceConfig{
Repository: customerRepo,
})
if err != nil {
logger.Error("failed to initialize customer service", "error", err)
os.Exit(1)
}
}

// Initialize Notification
var notificationService notification.Service

if conf.Notification.Enabled {
Expand Down Expand Up @@ -429,6 +455,7 @@ func main() {
PortalCORSEnabled: conf.Portal.CORS.Enabled,
ErrorHandler: errorsx.NewAppHandler(errorsx.NewSlogHandler(logger)),
// deps
Customer: customerService,
DebugConnector: debugConnector,
FeatureConnector: entitlementConnRegistry.Feature,
EntitlementConnector: entitlementConnRegistry.Entitlement,
Expand Down
Loading

0 comments on commit add50af

Please sign in to comment.