diff --git a/stapi-fastapi/CHANGELOG.md b/stapi-fastapi/CHANGELOG.md index d09e4ce..45022b1 100644 --- a/stapi-fastapi/CHANGELOG.md +++ b/stapi-fastapi/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Added - Add constants for route names to be used in link href generation +- Conformance url to product ([#85](https://github.com/stapi-spec/pystapi/pull/85)) ## Changed diff --git a/stapi-fastapi/src/stapi_fastapi/routers/product_router.py b/stapi-fastapi/src/stapi_fastapi/routers/product_router.py index ba18df3..6eeca19 100644 --- a/stapi-fastapi/src/stapi_fastapi/routers/product_router.py +++ b/stapi-fastapi/src/stapi_fastapi/routers/product_router.py @@ -18,6 +18,7 @@ from returns.maybe import Maybe, Some from returns.result import Failure, Success from stapi_pydantic import ( + Conformance, JsonSchemaModel, Link, OpportunityCollection, @@ -34,6 +35,7 @@ from stapi_fastapi.models.product import Product from stapi_fastapi.responses import GeoJSONResponse from stapi_fastapi.routers.route_names import ( + CONFORMANCE, CREATE_ORDER, GET_CONSTRAINTS, GET_OPPORTUNITY_COLLECTION, @@ -88,6 +90,15 @@ def __init__( tags=["Products"], ) + self.add_api_route( + path="/conformance", + endpoint=self.get_product_conformance, + name=f"{self.root_router.name}:{self.product.id}:{CONFORMANCE}", + methods=["GET"], + summary="Get conformance urls for the product", + tags=["Products"], + ) + self.add_api_route( path="/constraints", endpoint=self.get_product_constraints, @@ -179,6 +190,15 @@ 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}:{CONFORMANCE}", + ), + ), + rel="conformance", + type=TYPE_JSON, + ), Link( href=str( request.url_for( @@ -330,6 +350,12 @@ async def search_opportunities_async( case x: raise AssertionError(f"Expected code to be unreachable: {x}") + def get_product_conformance(self) -> Conformance: + """ + Return conformance urls of a specific product + """ + return Conformance.model_validate({"conforms_to": self.product.conformsTo}) + def get_product_constraints(self) -> JsonSchemaModel: """ Return supported constraints of a specific product diff --git a/stapi-fastapi/tests/test_product.py b/stapi-fastapi/tests/test_product.py index 980baea..cb80023 100644 --- a/stapi-fastapi/tests/test_product.py +++ b/stapi-fastapi/tests/test_product.py @@ -2,6 +2,7 @@ from fastapi import status from fastapi.testclient import TestClient from stapi_fastapi.models.product import Product +from stapi_pydantic import Conformance from .shared import pagination_tester @@ -19,7 +20,7 @@ def test_products_response(stapi_client: TestClient): @pytest.mark.parametrize("product_id", ["test-spotlight"]) -def test_product_response_self_link( +def test_product_response_links( product_id: str, stapi_client: TestClient, assert_link, @@ -32,12 +33,28 @@ def test_product_response_self_link( url = "GET /products" assert_link(url, body, "self", f"/products/{product_id}") + assert_link( + url, body, "conformance", f"/products/{product_id}/conformance" + ) # https://github.com/stapi-spec/stapi-spec/issues/253 assert_link(url, body, "constraints", f"/products/{product_id}/constraints") assert_link(url, body, "order-parameters", f"/products/{product_id}/order-parameters") assert_link(url, body, "opportunities", f"/products/{product_id}/opportunities") assert_link(url, body, "create-order", f"/products/{product_id}/orders", method="POST") +@pytest.mark.parametrize("product_id", ["test-spotlight"]) +def test_product_conformance_response( + product_id: str, + stapi_client: TestClient, +): + res = stapi_client.get(f"/products/{product_id}/constraints") + assert res.status_code == status.HTTP_200_OK + assert res.headers["Content-Type"] == "application/json" + + Conformance.model_validate(res.json()) + # TODO unsure what conformance products should support, as of yet + + @pytest.mark.parametrize("product_id", ["test-spotlight"]) def test_product_constraints_response( product_id: str, @@ -83,6 +100,11 @@ def test_get_products_pagination( "rel": "self", "type": "application/json", }, + { + "href": f"http://stapiserver/products/{product_id}/conformance", + "rel": "conformance", + "type": "application/json", + }, { "href": f"http://stapiserver/products/{product_id}/constraints", "rel": "constraints",