Skip to content

Commit

Permalink
add product order-parameters endpoint and links
Browse files Browse the repository at this point in the history
  • Loading branch information
Phil Varner committed Nov 12, 2024
1 parent e1f5d79 commit efb632e
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 14 deletions.
6 changes: 6 additions & 0 deletions bin/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
)
from stapi_fastapi.models.order import Order, OrderCollection
from stapi_fastapi.models.product import (
OrderParameters,
Product,
Provider,
ProviderRole,
Expand Down Expand Up @@ -82,6 +83,10 @@ class TestSpotlightProperties(OpportunityPropertiesBase):
off_nadir: int


class TestSpotlightOrderParameters(OrderParameters):
delivery_mechanism: str | None = None


order_db = MockOrderDB()
product_backend = MockProductBackend(order_db)
root_backend = MockRootBackend(order_db)
Expand All @@ -102,6 +107,7 @@ class TestSpotlightProperties(OpportunityPropertiesBase):
providers=[provider],
links=[],
constraints=TestSpotlightProperties,
order_parameters=TestSpotlightOrderParameters,
backend=product_backend,
)

Expand Down
13 changes: 12 additions & 1 deletion src/stapi_fastapi/models/product.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from enum import Enum
from typing import TYPE_CHECKING, Literal, Optional, Self

from pydantic import AnyHttpUrl, BaseModel, Field
from pydantic import AnyHttpUrl, BaseModel, ConfigDict, Field

from stapi_fastapi.models.opportunity import OpportunityPropertiesBase
from stapi_fastapi.models.shared import Link
Expand Down Expand Up @@ -32,6 +32,10 @@ def __init__(self, url: AnyHttpUrl | str, **kwargs):
super().__init__(url=url, **kwargs)


class OrderParameters(BaseModel):
model_config = ConfigDict(extra="allow")


class Product(BaseModel):
type_: Literal["Product"] = Field(default="Product", alias="type")
conformsTo: list[str] = Field(default_factory=list)
Expand All @@ -45,18 +49,21 @@ class Product(BaseModel):

# we don't want to include these in the model fields
_constraints: type[OpportunityPropertiesBase]
_order_parameters: type[OrderParameters]
_backend: ProductBackend

def __init__(
self,
*args,
backend: ProductBackend,
constraints: type[OpportunityPropertiesBase],
order_parameters: type[OrderParameters],
**kwargs,
) -> None:
super().__init__(*args, **kwargs)
self._backend = backend
self._constraints = constraints
self._order_parameters = order_parameters

@property
def backend(self: Self) -> ProductBackend:
Expand All @@ -66,6 +73,10 @@ def backend(self: Self) -> ProductBackend:
def constraints(self: Self) -> type[OpportunityPropertiesBase]:
return self._constraints

@property
def order_parameters(self: Self) -> type[OrderParameters]:
return self._order_parameters

def with_links(self: Self, links: list[Link] | None = None) -> Self:
if not links:
return self
Expand Down
33 changes: 33 additions & 0 deletions src/stapi_fastapi/routers/product_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ def __init__(
tags=["Products"],
)

self.add_api_route(
path="/order-parameters",
endpoint=self.get_product_order_parameters,
name=f"{self.root_router.name}:{self.product.id}:get-order-parameters",
methods=["GET"],
summary="Get order parameters for the product",
tags=["Products"],
)

self.add_api_route(
path="/order",
endpoint=self.create_order,
Expand All @@ -86,6 +95,24 @@ def get_product(self, request: Request) -> Product:
rel="self",
type=TYPE_JSON,
),
Link(
href=str(
request.url_for(
f"{self.root_router.name}:{self.product.id}:get-constraints",
),
),
rel="constraints",
type=TYPE_JSON,
),
Link(
href=str(
request.url_for(
f"{self.root_router.name}:{self.product.id}:get-order-parameters",
),
),
rel="order-parameters",
type=TYPE_JSON,
),
],
)

Expand All @@ -110,6 +137,12 @@ async def get_product_constraints(self: Self) -> JsonSchemaModel:
"""
return self.product.constraints

async def get_product_order_parameters(self: Self) -> JsonSchemaModel:
"""
Return supported constraints of a specific product
"""
return self.product.order_parameters

async def create_order(
self, payload: OpportunityRequest, request: Request, response: Response
) -> Order:
Expand Down
12 changes: 11 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
OpportunityPropertiesBase,
OpportunityRequest,
)
from stapi_fastapi.models.product import Product, Provider, ProviderRole
from stapi_fastapi.models.product import (
OrderParameters,
Product,
Provider,
ProviderRole,
)
from stapi_fastapi.routers.root_router import RootRouter

from .backends import MockOrderDB, MockProductBackend, MockRootBackend
Expand All @@ -26,6 +31,10 @@ class TestSpotlightProperties(OpportunityPropertiesBase):
off_nadir: int


class TestSpotlightOrderParameters(OrderParameters):
delivery_mechanism: str | None = None


@pytest.fixture(scope="session")
def base_url() -> Iterator[str]:
yield "http://stapiserver"
Expand Down Expand Up @@ -60,6 +69,7 @@ def mock_product_test_spotlight(
providers=[mock_provider],
links=[],
constraints=TestSpotlightProperties,
order_parameters=TestSpotlightOrderParameters,
backend=product_backend,
)

Expand Down
39 changes: 27 additions & 12 deletions tests/product_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
from fastapi import status
from fastapi.testclient import TestClient

from .utils import find_link


def test_products_response(stapi_client: TestClient):
res = stapi_client.get("/products")
Expand All @@ -21,17 +19,20 @@ def test_products_response(stapi_client: TestClient):
def test_product_response_self_link(
product_id: str,
stapi_client: TestClient,
url_for,
assert_link,
):
res = stapi_client.get(f"/products/{product_id}")
assert res.status_code == status.HTTP_200_OK
assert res.headers["Content-Type"] == "application/json"

data = res.json()
link = find_link(data["links"], "self")
assert link, "GET /products Link[rel=self] should exist"
assert link["type"] == "application/json"
assert link["href"] == url_for(f"/products/{product_id}")
body = res.json()

url = "GET /products"
assert_link(url, body, "self", f"/products/{product_id}")
assert_link(url, body, "constraints", f"/products/{product_id}/constraints")
assert_link(
url, body, "order-parameters", f"/products/{product_id}/order-parameters"
)


@pytest.mark.parametrize("product_id", ["test-spotlight"])
Expand All @@ -43,7 +44,21 @@ def test_product_constraints_response(
assert res.status_code == status.HTTP_200_OK
assert res.headers["Content-Type"] == "application/json"

data = res.json()
assert "properties" in data
assert "datetime" in data["properties"]
assert "off_nadir" in data["properties"]
json_schema = res.json()
assert "properties" in json_schema
assert "datetime" in json_schema["properties"]
assert "off_nadir" in json_schema["properties"]


@pytest.mark.parametrize("product_id", ["test-spotlight"])
def test_product_order_parameters_response(
product_id: str,
stapi_client: TestClient,
):
res = stapi_client.get(f"/products/{product_id}/order-parameters")
assert res.status_code == status.HTTP_200_OK
assert res.headers["Content-Type"] == "application/json"

json_schema = res.json()
assert "properties" in json_schema
assert "delivery_mechanism" in json_schema["properties"]

0 comments on commit efb632e

Please sign in to comment.