From bffd5a8e40dd3c4fcde6cbc3301311f586752256 Mon Sep 17 00:00:00 2001 From: P Date: Sat, 7 Mar 2026 21:59:42 +0200 Subject: [PATCH 1/9] feat: store apis --- smithy/model/common.smithy | 82 +++++++++++++++++++++ smithy/model/main.smithy | 5 +- smithy/model/store/store-apis.smithy | 100 ++++++++++++++++++++++++++ smithy/model/store/store-io.smithy | 86 ++++++++++++++++++++++ smithy/model/store/store-types.smithy | 41 +++++++++++ 5 files changed, 312 insertions(+), 2 deletions(-) create mode 100644 smithy/model/store/store-apis.smithy create mode 100644 smithy/model/store/store-io.smithy create mode 100644 smithy/model/store/store-types.smithy diff --git a/smithy/model/common.smithy b/smithy/model/common.smithy index 34d0b92..9d0d44b 100644 --- a/smithy/model/common.smithy +++ b/smithy/model/common.smithy @@ -17,3 +17,85 @@ string ResourceName @pattern("^https?://[a-zA-Z0-9\\-._~:/?#\\[\\]@!$&'()*+,;=%]+\\.(jpg|jpeg|png|gif)$") @length(min: 8, max: 255) string ImageUrl + +@pattern("^[a-zA-Z0-9\\-, ]+$") +@length(min: 8, max: 255) +string Description + +// All UTC offsets fall between this interval: [-12, 14]. +// Doubles are better suited since zones like `UTC+12:45` exist. +// See: https://en.wikipedia.org/wiki/List_of_UTC_offsets. +@range(min: -12, max: 14) +@documentation("UTC offsets for various globe zones") +double Timezone + +@range(min: 0, max: 59) +integer Minute + +@range(min: 0, max: 23) +integer Hour + +@range(min: -180, max: 180) +double Longitude + +@range(min: -90, max: 90) +double Latitude + +@range(min: 0, max: 100) +double Percentage + +@range(min: 0) +integer NaturalNumber + +@range(min: 0) +double PositiveDouble + +enum DayType { + MON = "MON" + TUE = "TUE" + WED = "WED" + THU = "THU" + FRI = "FRI" + SAT = "SAT" + SUN = "SUN" +} + +structure Time { + @required + hour: Hour + + @required + minute: Minute +} + +structure TimeRange { + @required + begin: Time + + @required + end: Time +} + +@mixin +@documentation("Parameters sent by the client to control pagination of the list results") +structure InputPagination { + @httpQuery("nextToken") + @documentation("An id used to retrieve the next page of results; leave empty for the first request") + nextToken: String + + @httpQuery("pageSize") + @default(100) + @documentation("The maximum number of items the client is requesting to be returned in this page") + pageSize: NaturalNumber +} + +@mixin +@documentation("Metadata returned to the client to assist in navigating paginated results") +structure OutputPagination { + @documentation("An id to be passed in the subsequent request to retrieve the next page; null if no more pages exist") + nextToken: String + + @required + @documentation("The actual number of items returned in the current response page.") + tokenCount: NaturalNumber +} diff --git a/smithy/model/main.smithy b/smithy/model/main.smithy index 4e67665..de39328 100644 --- a/smithy/model/main.smithy +++ b/smithy/model/main.smithy @@ -3,14 +3,15 @@ $version: "2" namespace com.shopping.inandout use aws.protocols#restJson1 -use com.shopping.inandout.brand#Brand +use com.shopping.inandout.store#Store use com.shopping.inandout.tsp#FindTspSolution @restJson1 +@paginated(inputToken: "nextToken", outputToken: "nextToken", pageSize: "pageSize", items: "tokens") service InAndOut { version: "2026-04-01" resources: [ - Brand + Store ] operations: [ FindTspSolution diff --git a/smithy/model/store/store-apis.smithy b/smithy/model/store/store-apis.smithy new file mode 100644 index 0000000..e50a6c9 --- /dev/null +++ b/smithy/model/store/store-apis.smithy @@ -0,0 +1,100 @@ +$version: "2" + +namespace com.shopping.inandout.store + +use com.shopping.inandout#Description +use com.shopping.inandout#ImageUrl +use com.shopping.inandout#InternalServerError +use com.shopping.inandout#InvalidInputError +use com.shopping.inandout#Latitude +use com.shopping.inandout#Longitude +use com.shopping.inandout#ResourceAlreadyExistsError +use com.shopping.inandout#ResourceName +use com.shopping.inandout#ResourceNotFoundError +use com.shopping.inandout#Timezone +use com.shopping.inandout#UUID + +resource Store { + identifiers: { + storeId: UUID + } + properties: { + name: ResourceName + brandId: UUID + description: Description + imageUrl: ImageUrl + timezone: Timezone + operatingHoursMap: OperatingHoursMap + longitude: Longitude + latitude: Latitude + createdAt: Timestamp + updatedAt: Timestamp + } + create: CreateStore + read: GetStore + list: ListStores + update: UpdateStore + delete: DeleteStore +} + +@http(method: "POST", uri: "/stores") +operation CreateStore { + input: CreateStoreInput + output: StoreSummary + errors: [ + InvalidInputError + ResourceAlreadyExistsError + InternalServerError + ] +} + +@readonly +@http(method: "GET", uri: "/stores/{storeId}") +@documentation("Returns additional brand details in order to avoid multiple network round-trips") +operation GetStore { + input: GetStoreInput + output: StoreSummary + errors: [ + InvalidInputError + ResourceNotFoundError + InternalServerError + ] +} + +@readonly +@paginated +@http(method: "GET", uri: "/stores") +@documentation("Returns additional brand details in order to avoid multiple network round-trips") +operation ListStores { + input: ListStoresInput + output: StoreSummaries + errors: [ + InvalidInputError + InternalServerError + ] +} + +@http(method: "PATCH", uri: "/stores/{storeId}") +@documentation("Non-idempotent cascading operation, creates/deletes internal resources as needed") +operation UpdateStore { + input: UpdateStoreInput + output: StoreSummary + errors: [ + InvalidInputError + ResourceNotFoundError + InternalServerError + ] +} + +@idempotent +@http(method: "DELETE", uri: "/stores/{storeId}") +@documentation("Not restricted cascading operation, deletes floors, stands, etc.") +operation DeleteStore { + input: DeleteStoreInput + output: StoreSummary + errors: [ + InvalidInputError + ResourceNotFoundError + InternalServerError + ] +} diff --git a/smithy/model/store/store-io.smithy b/smithy/model/store/store-io.smithy new file mode 100644 index 0000000..bf2ba28 --- /dev/null +++ b/smithy/model/store/store-io.smithy @@ -0,0 +1,86 @@ +$version: "2" + +namespace com.shopping.inandout.store + +use com.shopping.inandout#Description +use com.shopping.inandout#ImageUrl +use com.shopping.inandout#InputPagination +use com.shopping.inandout#Latitude +use com.shopping.inandout#Longitude +use com.shopping.inandout#PositiveDouble +use com.shopping.inandout#ResourceName +use com.shopping.inandout#Timezone +use com.shopping.inandout#UUID + +structure CreateStoreInput { + name: ResourceName + + @required + brandId: UUID + + description: Description + + imageUrl: ImageUrl + + timezone: Timezone + + operatingHoursMap: OperatingHoursMap + + longitude: Longitude + + latitude: Latitude +} + +structure GetStoreInput { + @required + @httpLabel + storeId: UUID +} + +@documentation("Retrieve a list of stores based on the provided queries") +structure ListStoresInput with [InputPagination] { + @httpQuery("name") + name: ResourceName + + @httpQuery("isOpen") + isOpen: Boolean + + @httpQuery("userLongitude") + userLongitude: Longitude + + @httpQuery("userLatitude") + userLatitude: Latitude + + // ! User location must be provided in order for the below queries to work. + @httpQuery("maxDistance") + @documentation("Distance measured in kilometers") + maxDistance: PositiveDouble +} + +structure UpdateStoreInput { + @required + @httpLabel + storeId: UUID + + name: ResourceName + + brandId: UUID + + description: Description + + imageUrl: ImageUrl + + timezone: Timezone + + operatingHoursMap: OperatingHoursMap + + longitude: Longitude + + latitude: Latitude +} + +structure DeleteStoreInput { + @required + @httpLabel + storeId: UUID +} diff --git a/smithy/model/store/store-types.smithy b/smithy/model/store/store-types.smithy new file mode 100644 index 0000000..c0e83ef --- /dev/null +++ b/smithy/model/store/store-types.smithy @@ -0,0 +1,41 @@ +$version: "2" + +namespace com.shopping.inandout.store + +use com.shopping.inandout#DayType +use com.shopping.inandout#Description +use com.shopping.inandout#ImageUrl +use com.shopping.inandout#Latitude +use com.shopping.inandout#Longitude +use com.shopping.inandout#OutputPagination +use com.shopping.inandout#ResourceName +use com.shopping.inandout#TimeRange +use com.shopping.inandout#Timezone +use com.shopping.inandout#UUID + +map OperatingHoursMap { + key: DayType + value: TimeRange +} + +structure StoreSummary { + name: ResourceName + brandId: UUID + description: Description + imageUrl: ImageUrl + timezone: Timezone + operatingHoursMap: OperatingHoursMap + longitude: Longitude + latitude: Latitude + createdAt: Timestamp + updatedAt: Timestamp +} + +list StoreSummaryList { + member: StoreSummary +} + +// This is needed since lists or other similar collections can not be used as input/output for operations. +structure StoreSummaries with [OutputPagination] { + tokens: StoreSummaryList +} From cffcbc446b3d820596dd71585640916f86262ba6 Mon Sep 17 00:00:00 2001 From: P Date: Sat, 7 Mar 2026 22:59:02 +0200 Subject: [PATCH 2/9] fix: store operation output now returns the store id as well --- smithy/model/store/store-types.smithy | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/smithy/model/store/store-types.smithy b/smithy/model/store/store-types.smithy index c0e83ef..9648755 100644 --- a/smithy/model/store/store-types.smithy +++ b/smithy/model/store/store-types.smithy @@ -19,15 +19,31 @@ map OperatingHoursMap { } structure StoreSummary { + @required + @resourceIdentifier("Store") + storeId: UUID + name: ResourceName + + @required brandId: UUID + description: Description + imageUrl: ImageUrl + timezone: Timezone + operatingHoursMap: OperatingHoursMap + longitude: Longitude + latitude: Latitude + + @required createdAt: Timestamp + + @required updatedAt: Timestamp } From e3c0c519d97e51ef9669a19249695f868a8d4f1a Mon Sep 17 00:00:00 2001 From: P Date: Sat, 7 Mar 2026 23:06:42 +0200 Subject: [PATCH 3/9] fix: resourceIdentifier trait value for storeSummary structure --- smithy/model/store/store-types.smithy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smithy/model/store/store-types.smithy b/smithy/model/store/store-types.smithy index 9648755..7b73699 100644 --- a/smithy/model/store/store-types.smithy +++ b/smithy/model/store/store-types.smithy @@ -20,7 +20,7 @@ map OperatingHoursMap { structure StoreSummary { @required - @resourceIdentifier("Store") + @resourceIdentifier("storeId") storeId: UUID name: ResourceName From d2dee3ab07f7ebe743d7bb3928438a245d3a3b82 Mon Sep 17 00:00:00 2001 From: P Date: Sat, 7 Mar 2026 23:13:05 +0200 Subject: [PATCH 4/9] removed useless trait --- smithy/model/store/store-types.smithy | 1 - 1 file changed, 1 deletion(-) diff --git a/smithy/model/store/store-types.smithy b/smithy/model/store/store-types.smithy index 7b73699..5983ab9 100644 --- a/smithy/model/store/store-types.smithy +++ b/smithy/model/store/store-types.smithy @@ -20,7 +20,6 @@ map OperatingHoursMap { structure StoreSummary { @required - @resourceIdentifier("storeId") storeId: UUID name: ResourceName From e395320cff4b3832487e1ebddc940e01990e62cc Mon Sep 17 00:00:00 2001 From: P Date: Sat, 7 Mar 2026 23:23:56 +0200 Subject: [PATCH 5/9] feat: GeoCoordinates --- smithy/model/common.smithy | 8 ++++++++ smithy/model/store/store-apis.smithy | 8 +++----- smithy/model/store/store-io.smithy | 9 +++------ smithy/model/store/store-types.smithy | 9 +++------ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/smithy/model/common.smithy b/smithy/model/common.smithy index 9d0d44b..f352639 100644 --- a/smithy/model/common.smithy +++ b/smithy/model/common.smithy @@ -50,6 +50,14 @@ integer NaturalNumber @range(min: 0) double PositiveDouble +structure GeoCoordinates { + @required + longitude: Longitude + + @required + latitude: Latitude +} + enum DayType { MON = "MON" TUE = "TUE" diff --git a/smithy/model/store/store-apis.smithy b/smithy/model/store/store-apis.smithy index e50a6c9..3f0ebdc 100644 --- a/smithy/model/store/store-apis.smithy +++ b/smithy/model/store/store-apis.smithy @@ -3,11 +3,10 @@ $version: "2" namespace com.shopping.inandout.store use com.shopping.inandout#Description +use com.shopping.inandout#GeoCoordinates use com.shopping.inandout#ImageUrl use com.shopping.inandout#InternalServerError use com.shopping.inandout#InvalidInputError -use com.shopping.inandout#Latitude -use com.shopping.inandout#Longitude use com.shopping.inandout#ResourceAlreadyExistsError use com.shopping.inandout#ResourceName use com.shopping.inandout#ResourceNotFoundError @@ -23,10 +22,9 @@ resource Store { brandId: UUID description: Description imageUrl: ImageUrl - timezone: Timezone + geoCoordinates: GeoCoordinates operatingHoursMap: OperatingHoursMap - longitude: Longitude - latitude: Latitude + timezone: Timezone createdAt: Timestamp updatedAt: Timestamp } diff --git a/smithy/model/store/store-io.smithy b/smithy/model/store/store-io.smithy index bf2ba28..35fabc9 100644 --- a/smithy/model/store/store-io.smithy +++ b/smithy/model/store/store-io.smithy @@ -3,6 +3,7 @@ $version: "2" namespace com.shopping.inandout.store use com.shopping.inandout#Description +use com.shopping.inandout#GeoCoordinates use com.shopping.inandout#ImageUrl use com.shopping.inandout#InputPagination use com.shopping.inandout#Latitude @@ -26,9 +27,7 @@ structure CreateStoreInput { operatingHoursMap: OperatingHoursMap - longitude: Longitude - - latitude: Latitude + geoCoordinates: GeoCoordinates } structure GetStoreInput { @@ -74,9 +73,7 @@ structure UpdateStoreInput { operatingHoursMap: OperatingHoursMap - longitude: Longitude - - latitude: Latitude + geoCoordinates: GeoCoordinates } structure DeleteStoreInput { diff --git a/smithy/model/store/store-types.smithy b/smithy/model/store/store-types.smithy index 5983ab9..57fc300 100644 --- a/smithy/model/store/store-types.smithy +++ b/smithy/model/store/store-types.smithy @@ -4,9 +4,8 @@ namespace com.shopping.inandout.store use com.shopping.inandout#DayType use com.shopping.inandout#Description +use com.shopping.inandout#GeoCoordinates use com.shopping.inandout#ImageUrl -use com.shopping.inandout#Latitude -use com.shopping.inandout#Longitude use com.shopping.inandout#OutputPagination use com.shopping.inandout#ResourceName use com.shopping.inandout#TimeRange @@ -31,13 +30,11 @@ structure StoreSummary { imageUrl: ImageUrl - timezone: Timezone + geoCoordinates: GeoCoordinates operatingHoursMap: OperatingHoursMap - longitude: Longitude - - latitude: Latitude + timezone: Timezone @required createdAt: Timestamp From 26d51873d13a65965d5d8f17a887a7b6f99efcf7 Mon Sep 17 00:00:00 2001 From: P Date: Sat, 7 Mar 2026 23:33:50 +0200 Subject: [PATCH 6/9] rebasing --- smithy/model/main.smithy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/smithy/model/main.smithy b/smithy/model/main.smithy index de39328..d3bc69a 100644 --- a/smithy/model/main.smithy +++ b/smithy/model/main.smithy @@ -3,6 +3,7 @@ $version: "2" namespace com.shopping.inandout use aws.protocols#restJson1 +use com.shopping.inandout.brand#Brand use com.shopping.inandout.store#Store use com.shopping.inandout.tsp#FindTspSolution @@ -11,6 +12,7 @@ use com.shopping.inandout.tsp#FindTspSolution service InAndOut { version: "2026-04-01" resources: [ + Brand Store ] operations: [ From 4424b87145f4aa2fff6e8829cb63b908408b0845 Mon Sep 17 00:00:00 2001 From: Petru Braha Date: Sat, 7 Mar 2026 23:44:15 +0200 Subject: [PATCH 7/9] reorder of shapes --- smithy/model/common.smithy | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/smithy/model/common.smithy b/smithy/model/common.smithy index f352639..82d6c81 100644 --- a/smithy/model/common.smithy +++ b/smithy/model/common.smithy @@ -22,25 +22,6 @@ string ImageUrl @length(min: 8, max: 255) string Description -// All UTC offsets fall between this interval: [-12, 14]. -// Doubles are better suited since zones like `UTC+12:45` exist. -// See: https://en.wikipedia.org/wiki/List_of_UTC_offsets. -@range(min: -12, max: 14) -@documentation("UTC offsets for various globe zones") -double Timezone - -@range(min: 0, max: 59) -integer Minute - -@range(min: 0, max: 23) -integer Hour - -@range(min: -180, max: 180) -double Longitude - -@range(min: -90, max: 90) -double Latitude - @range(min: 0, max: 100) double Percentage @@ -50,6 +31,12 @@ integer NaturalNumber @range(min: 0) double PositiveDouble +@range(min: -180, max: 180) +double Longitude + +@range(min: -90, max: 90) +double Latitude + structure GeoCoordinates { @required longitude: Longitude @@ -68,6 +55,19 @@ enum DayType { SUN = "SUN" } +// All UTC offsets fall between this interval: [-12, 14]. +// Doubles are better suited since zones like `UTC+12:45` exist. +// See: https://en.wikipedia.org/wiki/List_of_UTC_offsets. +@range(min: -12, max: 14) +@documentation("UTC offsets for various globe zones") +double Timezone + +@range(min: 0, max: 59) +integer Minute + +@range(min: 0, max: 23) +integer Hour + structure Time { @required hour: Hour From 1777719c539ce5dbe4dc78d91a186d11b22352ef Mon Sep 17 00:00:00 2001 From: Petru Braha Date: Sat, 7 Mar 2026 23:44:28 +0200 Subject: [PATCH 8/9] feat: Brand references --- smithy/model/store/store-io.smithy | 11 +++++++++++ smithy/model/store/store-types.smithy | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/smithy/model/store/store-io.smithy b/smithy/model/store/store-io.smithy index 35fabc9..fd3121a 100644 --- a/smithy/model/store/store-io.smithy +++ b/smithy/model/store/store-io.smithy @@ -12,7 +12,13 @@ use com.shopping.inandout#PositiveDouble use com.shopping.inandout#ResourceName use com.shopping.inandout#Timezone use com.shopping.inandout#UUID +use com.shopping.inandout.brand#Brand +@references([ + { + resource: Brand + } +]) structure CreateStoreInput { name: ResourceName @@ -56,6 +62,11 @@ structure ListStoresInput with [InputPagination] { maxDistance: PositiveDouble } +@references([ + { + resource: Brand + } +]) structure UpdateStoreInput { @required @httpLabel diff --git a/smithy/model/store/store-types.smithy b/smithy/model/store/store-types.smithy index 57fc300..9c204da 100644 --- a/smithy/model/store/store-types.smithy +++ b/smithy/model/store/store-types.smithy @@ -11,12 +11,18 @@ use com.shopping.inandout#ResourceName use com.shopping.inandout#TimeRange use com.shopping.inandout#Timezone use com.shopping.inandout#UUID +use com.shopping.inandout.brand#Brand map OperatingHoursMap { key: DayType value: TimeRange } +@references([ + { + resource: Brand + } +]) structure StoreSummary { @required storeId: UUID From 789540d5167ca6072a3713a2adea73e651b4cbd6 Mon Sep 17 00:00:00 2001 From: Petru Braha Date: Sat, 7 Mar 2026 23:47:50 +0200 Subject: [PATCH 9/9] removed falsy documentation --- smithy/model/store/store-apis.smithy | 3 --- smithy/model/store/store-io.smithy | 1 - 2 files changed, 4 deletions(-) diff --git a/smithy/model/store/store-apis.smithy b/smithy/model/store/store-apis.smithy index 3f0ebdc..9f25ceb 100644 --- a/smithy/model/store/store-apis.smithy +++ b/smithy/model/store/store-apis.smithy @@ -48,7 +48,6 @@ operation CreateStore { @readonly @http(method: "GET", uri: "/stores/{storeId}") -@documentation("Returns additional brand details in order to avoid multiple network round-trips") operation GetStore { input: GetStoreInput output: StoreSummary @@ -62,7 +61,6 @@ operation GetStore { @readonly @paginated @http(method: "GET", uri: "/stores") -@documentation("Returns additional brand details in order to avoid multiple network round-trips") operation ListStores { input: ListStoresInput output: StoreSummaries @@ -73,7 +71,6 @@ operation ListStores { } @http(method: "PATCH", uri: "/stores/{storeId}") -@documentation("Non-idempotent cascading operation, creates/deletes internal resources as needed") operation UpdateStore { input: UpdateStoreInput output: StoreSummary diff --git a/smithy/model/store/store-io.smithy b/smithy/model/store/store-io.smithy index fd3121a..a047eb5 100644 --- a/smithy/model/store/store-io.smithy +++ b/smithy/model/store/store-io.smithy @@ -42,7 +42,6 @@ structure GetStoreInput { storeId: UUID } -@documentation("Retrieve a list of stores based on the provided queries") structure ListStoresInput with [InputPagination] { @httpQuery("name") name: ResourceName