From 89add4914a9ebdb4d24cc2d4012bae7a1ae7a24f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Tailland?= Date: Thu, 20 Aug 2026 13:24:10 +0200 Subject: [PATCH] First commit --- .gitignore | 2 + dev/flux-kustomization.yaml | 27 ++ dev/kong/kongplugin.yaml | 30 ++ dev/kong/kustomization.yaml | 14 + dev/kong/pluginbindings.yaml | 21 ++ dev/kong/routes.yaml | 285 ++++++++++++++ dev/kong/service.yaml | 25 ++ kong/httproute.yaml | 1 - kong/kongplugin.yaml | 1 - openapi.yaml | 707 +++++++++++++++++++++++++++++++++++ 10 files changed, 1111 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 dev/flux-kustomization.yaml create mode 100644 dev/kong/kongplugin.yaml create mode 100644 dev/kong/kustomization.yaml create mode 100644 dev/kong/pluginbindings.yaml create mode 100644 dev/kong/routes.yaml create mode 100644 dev/kong/service.yaml delete mode 100644 kong/httproute.yaml delete mode 100644 kong/kongplugin.yaml create mode 100644 openapi.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d42b71 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +*.swp \ No newline at end of file diff --git a/dev/flux-kustomization.yaml b/dev/flux-kustomization.yaml new file mode 100644 index 0000000..682f2f6 --- /dev/null +++ b/dev/flux-kustomization.yaml @@ -0,0 +1,27 @@ +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: catalog-dev-api + namespace: flux-system +spec: + interval: 10m + sourceRef: + kind: GitRepository + name: catalog-api + path: ./dev/kong + prune: true + dependsOn: + - name: catalog-dev-api-gateway + postBuild: + substitute: + NAME: catalog-dev + NAMESPACE: catalog + CONTROL_PLANE_REF_NAME: catalog-dev-bkphl + BACKEND_HOST: classic-models-api.classic-models.svc.cluster.local + # PLACEHOLDER audience name — no Keycloak client for "catalog-api" + # exists yet, this will reject every real token until that client is + # created. + API_AUDIENCE: '["catalog-api"]' + substituteFrom: + - kind: ConfigMap + name: dataplane-template-defaults diff --git a/dev/kong/kongplugin.yaml b/dev/kong/kongplugin.yaml new file mode 100644 index 0000000..78c1f60 --- /dev/null +++ b/dev/kong/kongplugin.yaml @@ -0,0 +1,30 @@ +# Per-API audience check — narrows on top of the domain-wide whitelist +# check already enforced globally (k8s-platform/dataplane-globalpolicy-template, +# scope: GlobalInControlPlane). Defense in depth: both instances run +# independently on every request (verified Kong behavior, see STATUS.md). +# +# PLACEHOLDER-in-spirit: no Keycloak client named "catalog-api" exists yet +# (only classic-models-api's own client/mapper does) — this will reject +# every real token until that client + its oidc-audience-mapper are created. +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: ${NAME}-catalog-api-openid-connect + namespace: ${NAMESPACE} +plugin: openid-connect +config: + issuer: ${OIDC_ISSUER} + # Whole YAML flow-sequence as one string var, same reason as + # JWT_AUDIENCE_WHITELIST in the global template — postBuild.substitute + # does plain text substitution, not list generation. + audience_required: ${API_AUDIENCE} + auth_methods: + - bearer + display_errors: false + # This Control Plane enforces a global tls_certificate_verify option + # (Konnect-side, not set by us) that rejects any plugin instance whose TLS + # verification is off — openid-connect defaults to ssl_verify: false, + # which silently broke the DataPlane's config sync entirely (verified via + # DataPlane pod logs: "ssl_verify cannot be disabled"). Explicit true is + # the correct fix anyway: verify the issuer's cert when fetching JWKS. + ssl_verify: true diff --git a/dev/kong/kustomization.yaml b/dev/kong/kustomization.yaml new file mode 100644 index 0000000..d104ce4 --- /dev/null +++ b/dev/kong/kustomization.yaml @@ -0,0 +1,14 @@ +# Explicit on purpose, unlike catalog-api's earlier (removed) layout — +# kong-kustomization.yaml (the Flux CR) now lives in this same directory, +# and Flux's path-without-a-kustomization.yaml auto-generation scans every +# yaml file present, indiscriminately. Without this explicit list, it would +# include kong-kustomization.yaml itself as a managed resource — the +# Kustomization would end up applying (and, with prune: true, potentially +# pruning) its own object. Listing resources explicitly avoids that. +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - service.yaml + - routes.yaml + - kongplugin.yaml + - pluginbindings.yaml diff --git a/dev/kong/pluginbindings.yaml b/dev/kong/pluginbindings.yaml new file mode 100644 index 0000000..e7b5e36 --- /dev/null +++ b/dev/kong/pluginbindings.yaml @@ -0,0 +1,21 @@ +# Bound to the natively-authored KongService (../service.yaml), not to +# individual routes — all of catalog-api's routes share the same audience, +# same as tasks-api's pattern. Unlike the earlier HTTPRoute-derived +# KongService, this name is ours and stable across reconciles. +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongPluginBinding +metadata: + name: ${NAME}-catalog-api-openid-connect-binding + namespace: ${NAMESPACE} +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + pluginRef: + name: ${NAME}-catalog-api-openid-connect + targets: + serviceRef: + group: configuration.konghq.com + kind: KongService + name: ${NAME}-catalog-api diff --git a/dev/kong/routes.yaml b/dev/kong/routes.yaml new file mode 100644 index 0000000..8e40c7f --- /dev/null +++ b/dev/kong/routes.yaml @@ -0,0 +1,285 @@ +# One KongRoute per operation in ../openapi.yaml (14 total — same +# granularity as ~/dev/kong/kube/apis/tasks-api/routes.yaml: split by +# operation even when two share a path, so a future per-operation policy +# doesn't require restructuring). Regex paths use Kong's own `~` syntax +# directly — no auto-translation layer involved this time (that was +# specific to the HTTPRoute path we abandoned). +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-listproductlines + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_listproductlines + methods: + - GET + - OPTIONS + paths: + - /classic-models/api/v1/productlines/ + strip_path: false + tags: + - catalog +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-createproductline + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_createproductline + methods: + - POST + - OPTIONS + paths: + - /classic-models/api/v1/productlines/ + strip_path: false + tags: + - catalog +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-getproductline + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_getproductline + methods: + - GET + - OPTIONS + paths: + - ~/classic-models/api/v1/productlines/(?[^#?/]+)/$ + strip_path: false + tags: + - catalog +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-updateproductline + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_updateproductline + methods: + - PUT + - OPTIONS + paths: + - ~/classic-models/api/v1/productlines/(?[^#?/]+)/$ + strip_path: false + tags: + - catalog +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-patchproductline + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_patchproductline + methods: + - PATCH + - OPTIONS + paths: + - ~/classic-models/api/v1/productlines/(?[^#?/]+)/$ + strip_path: false + tags: + - catalog +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-deleteproductline + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_deleteproductline + methods: + - DELETE + - OPTIONS + paths: + - ~/classic-models/api/v1/productlines/(?[^#?/]+)/$ + strip_path: false + tags: + - catalog +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-listproductlineproducts + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_listproductlineproducts + methods: + - GET + - OPTIONS + paths: + - ~/classic-models/api/v1/productlines/(?[^#?/]+)/products/$ + strip_path: false + tags: + - catalog +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-listproducts + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_listproducts + methods: + - GET + - OPTIONS + paths: + - /classic-models/api/v1/products/ + strip_path: false + tags: + - catalog +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-createproduct + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_createproduct + methods: + - POST + - OPTIONS + paths: + - /classic-models/api/v1/products/ + strip_path: false + tags: + - catalog +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-getproduct + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_getproduct + methods: + - GET + - OPTIONS + paths: + - ~/classic-models/api/v1/products/(?[^#?/]+)/$ + strip_path: false + tags: + - catalog +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-updateproduct + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_updateproduct + methods: + - PUT + - OPTIONS + paths: + - ~/classic-models/api/v1/products/(?[^#?/]+)/$ + strip_path: false + tags: + - catalog +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-patchproduct + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_patchproduct + methods: + - PATCH + - OPTIONS + paths: + - ~/classic-models/api/v1/products/(?[^#?/]+)/$ + strip_path: false + tags: + - catalog +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-deleteproduct + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_deleteproduct + methods: + - DELETE + - OPTIONS + paths: + - ~/classic-models/api/v1/products/(?[^#?/]+)/$ + strip_path: false + tags: + - catalog +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongRoute +metadata: + name: ${NAME}-catalog-api-getproductorderdetails + namespace: ${NAMESPACE} +spec: + serviceRef: + type: namespacedRef + namespacedRef: + name: ${NAME}-catalog-api + name: catalog-api_getproductorderdetails + methods: + - GET + - OPTIONS + paths: + - ~/classic-models/api/v1/products/(?[^#?/]+)/order-details/$ + strip_path: false + tags: + - catalog diff --git a/dev/kong/service.yaml b/dev/kong/service.yaml new file mode 100644 index 0000000..8bedbe1 --- /dev/null +++ b/dev/kong/service.yaml @@ -0,0 +1,25 @@ +# host is a plain DNS string, not a Kubernetes object reference — unlike +# HTTPRoute's backendRefs, this needs no ReferenceGrant to cross into the +# classic-models namespace. +# +# metadata.name carries the ${NAME} (env) prefix because this domain's +# environments share one k8s namespace (see dataplane-catalog's own +# NAME/NAMESPACE split) — spec.name (Kong/Konnect-side) doesn't need it, +# each env already has its own isolated Control Plane. +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongService +metadata: + name: ${NAME}-catalog-api + namespace: ${NAMESPACE} +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + name: catalog-api + host: ${BACKEND_HOST} + port: 8000 + protocol: http + path: / + tags: + - catalog diff --git a/kong/httproute.yaml b/kong/httproute.yaml deleted file mode 100644 index 4c638f0..0000000 --- a/kong/httproute.yaml +++ /dev/null @@ -1 +0,0 @@ -# TODO: HTTPRoute for catalog's resources diff --git a/kong/kongplugin.yaml b/kong/kongplugin.yaml deleted file mode 100644 index 4871cdd..0000000 --- a/kong/kongplugin.yaml +++ /dev/null @@ -1 +0,0 @@ -# TODO: KongPlugin(s) specific to catalog diff --git a/openapi.yaml b/openapi.yaml new file mode 100644 index 0000000..f340549 --- /dev/null +++ b/openapi.yaml @@ -0,0 +1,707 @@ +openapi: 3.0.3 +info: + title: Classic Models API — Catalog domain + version: 4.7.0 + description: Catalog domain (productlines, products) subset of the shared classic-models-api backend. Kong exposes only these paths for the catalog domain's Control Plane. +paths: + /classic-models/api/v1/productlines/: + post: + operationId: create_product_line + description: Add a new product line category to the system. + summary: Create a new product line + tags: + - Product Lines + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProductLineRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/ProductLineRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/ProductLineRequest' + required: true + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "201": + content: + application/json: + schema: + $ref: '#/components/schemas/ProductLine' + description: "" + get: + operationId: list_product_lines + description: Retrieve a paginated list of all product line categories in the system. + summary: List all product lines + parameters: + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + tags: + - Product Lines + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedProductLineList' + description: "" + /classic-models/api/v1/productlines/{productline}/: + patch: + operationId: patch_product_line + description: Update specific fields of an existing product line. + summary: Partially update a product line + parameters: + - in: path + name: productline + schema: + type: string + description: A unique value identifying this product line. + required: true + tags: + - Product Lines + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedProductLineRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedProductLineRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedProductLineRequest' + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ProductLine' + description: "" + get: + operationId: get_product_line + description: Retrieve detailed information about a specific product line by its identifier. + summary: Get a specific product line + parameters: + - in: path + name: productline + schema: + type: string + description: A unique value identifying this product line. + required: true + tags: + - Product Lines + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ProductLine' + description: "" + put: + operationId: update_product_line + description: Update all fields of an existing product line. + summary: Update a product line + parameters: + - in: path + name: productline + schema: + type: string + description: A unique value identifying this product line. + required: true + tags: + - Product Lines + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProductLineRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/ProductLineRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/ProductLineRequest' + required: true + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ProductLine' + description: "" + delete: + operationId: delete_product_line + description: Remove a product line from the system. + summary: Delete a product line + parameters: + - in: path + name: productline + schema: + type: string + description: A unique value identifying this product line. + required: true + tags: + - Product Lines + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "204": + description: No response body + /classic-models/api/v1/productlines/{productline}/products/: + get: + operationId: get_product_line_products + description: Retrieve all products in a specific product line category. This endpoint allows browsing products by category. + summary: Get products by product line + parameters: + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - in: path + name: productline + schema: + type: string + description: The product line identifier + required: true + tags: + - Product Lines + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedProductList' + description: "" + /classic-models/api/v1/products/: + post: + operationId: create_product + description: Add a new product to the catalog with all required information. + summary: Create a new product + tags: + - Products + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProductRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/ProductRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/ProductRequest' + required: true + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "201": + content: + application/json: + schema: + $ref: '#/components/schemas/Product' + description: "" + get: + operationId: list_products + description: Retrieve a paginated list of all products in the catalog with their details. + summary: List all products + parameters: + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + tags: + - Products + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedProductList' + description: "" + /classic-models/api/v1/products/{productcode}/: + patch: + operationId: patch_product + description: Update specific fields of an existing product. + summary: Partially update a product + parameters: + - in: path + name: productcode + schema: + type: string + description: A unique value identifying this product. + required: true + tags: + - Products + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedProductRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedProductRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedProductRequest' + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/Product' + description: "" + get: + operationId: get_product + description: Retrieve detailed information about a specific product by its code. + summary: Get a specific product + parameters: + - in: path + name: productcode + schema: + type: string + description: A unique value identifying this product. + required: true + tags: + - Products + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/Product' + description: "" + put: + operationId: update_product + description: Update all fields of an existing product in the catalog. + summary: Update a product + parameters: + - in: path + name: productcode + schema: + type: string + description: A unique value identifying this product. + required: true + tags: + - Products + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProductRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/ProductRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/ProductRequest' + required: true + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/Product' + description: "" + delete: + operationId: delete_product + description: Remove a product from the catalog. + summary: Delete a product + parameters: + - in: path + name: productcode + schema: + type: string + description: A unique value identifying this product. + required: true + tags: + - Products + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "204": + description: No response body + /classic-models/api/v1/products/{productcode}/order-details/: + get: + operationId: get_product_order_details + description: Retrieve all order details (sales) for a specific product. This endpoint provides the complete sales history for the product. + summary: Get product order history + parameters: + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - in: path + name: productcode + schema: + type: string + description: The product code + required: true + tags: + - Products + security: + - ApiKeyAuth: [] + - JWTAuth: [] + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedOrderdetailList' + description: "" +components: + schemas: + Orderdetail: + type: object + description: Order line items with product details + properties: + id: + type: integer + readOnly: true + quantityordered: + type: integer + maximum: 2147483647 + minimum: -2147483648 + priceeach: + type: string + format: decimal + pattern: ^-?\d{0,8}(?:\.\d{0,2})?$ + orderlinenumber: + type: integer + maximum: 32767 + minimum: -32768 + ordernumber: + type: integer + maximum: 2147483647 + minimum: -2147483648 + productcode: + type: string + required: + - id + - orderlinenumber + - ordernumber + - priceeach + - productcode + - quantityordered + PaginatedOrderdetailList: + type: object + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=4 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=2 + results: + type: array + items: + $ref: '#/components/schemas/Orderdetail' + PaginatedProductLineList: + type: object + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=4 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=2 + results: + type: array + items: + $ref: '#/components/schemas/ProductLine' + PaginatedProductList: + type: object + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=4 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=2 + results: + type: array + items: + $ref: '#/components/schemas/Product' + PatchedProductLineRequest: + type: object + description: Product line category information + properties: + productline: + type: string + minLength: 1 + maxLength: 50 + textdescription: + type: string + nullable: true + maxLength: 4000 + htmldescription: + type: string + nullable: true + PatchedProductRequest: + type: object + description: Product catalog information + properties: + productcode: + type: string + minLength: 1 + maxLength: 15 + productname: + type: string + minLength: 1 + maxLength: 70 + productscale: + type: string + minLength: 1 + maxLength: 10 + productvendor: + type: string + minLength: 1 + maxLength: 50 + productdescription: + type: string + minLength: 1 + quantityinstock: + type: integer + maximum: 32767 + minimum: -32768 + buyprice: + type: string + format: decimal + pattern: ^-?\d{0,8}(?:\.\d{0,2})?$ + msrp: + type: string + format: decimal + pattern: ^-?\d{0,8}(?:\.\d{0,2})?$ + productline: + type: string + minLength: 1 + Product: + type: object + description: Product catalog information + properties: + productcode: + type: string + maxLength: 15 + productname: + type: string + maxLength: 70 + productscale: + type: string + maxLength: 10 + productvendor: + type: string + maxLength: 50 + productdescription: + type: string + quantityinstock: + type: integer + maximum: 32767 + minimum: -32768 + buyprice: + type: string + format: decimal + pattern: ^-?\d{0,8}(?:\.\d{0,2})?$ + msrp: + type: string + format: decimal + pattern: ^-?\d{0,8}(?:\.\d{0,2})?$ + productline: + type: string + required: + - buyprice + - msrp + - productcode + - productdescription + - productline + - productname + - productscale + - productvendor + - quantityinstock + ProductLine: + type: object + description: Product line category information + properties: + productline: + type: string + maxLength: 50 + textdescription: + type: string + nullable: true + maxLength: 4000 + htmldescription: + type: string + nullable: true + image: + type: string + format: byte + readOnly: true + nullable: true + required: + - image + - productline + ProductLineRequest: + type: object + description: Product line category information + properties: + productline: + type: string + minLength: 1 + maxLength: 50 + textdescription: + type: string + nullable: true + maxLength: 4000 + htmldescription: + type: string + nullable: true + required: + - productline + ProductRequest: + type: object + description: Product catalog information + properties: + productcode: + type: string + minLength: 1 + maxLength: 15 + productname: + type: string + minLength: 1 + maxLength: 70 + productscale: + type: string + minLength: 1 + maxLength: 10 + productvendor: + type: string + minLength: 1 + maxLength: 50 + productdescription: + type: string + minLength: 1 + quantityinstock: + type: integer + maximum: 32767 + minimum: -32768 + buyprice: + type: string + format: decimal + pattern: ^-?\d{0,8}(?:\.\d{0,2})?$ + msrp: + type: string + format: decimal + pattern: ^-?\d{0,8}(?:\.\d{0,2})?$ + productline: + type: string + minLength: 1 + required: + - buyprice + - msrp + - productcode + - productdescription + - productline + - productname + - productscale + - productvendor + - quantityinstock + securitySchemes: + ApiKeyAuth: + type: apiKey + in: header + name: X-API-Key + description: API key authentication using X-API-Key header + JWTAuth: + type: http + scheme: bearer + bearerFormat: JWT +servers: + - url: http://localhost:8000 + description: API Server