Boavizta / boaviztapi

🛠 Giving access to BOAVIZTA reference data and methodologies trough a RESTful API
GNU Affero General Public License v3.0
68 stars 23 forks source link

Insufficient parameters in request leads to http 500 error - CPU example #74

Closed bpetit closed 2 years ago

bpetit commented 2 years ago

Bug description

Sending a request with incomplete data leads to a 500 error. Like :

INFO:     172.17.0.1:45700 - "POST /v1/component/cpu HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/uvicorn/protocols/http/h11_impl.py", line 366, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/usr/local/lib/python3.7/site-packages/uvicorn/middleware/proxy_headers.py", line 75, in __call__
    return await self.app(scope, receive, send)
  File "/usr/local/lib/python3.7/site-packages/fastapi/applications.py", line 261, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.7/site-packages/starlette/applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.7/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc
  File "/usr/local/lib/python3.7/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.7/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc
  File "/usr/local/lib/python3.7/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.7/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/usr/local/lib/python3.7/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 656, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 259, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 61, in app
    response = await func(request)
  File "/usr/local/lib/python3.7/site-packages/fastapi/routing.py", line 228, in app
    dependant=dependant, values=values, is_coroutine=is_coroutine
  File "/usr/local/lib/python3.7/site-packages/fastapi/routing.py", line 160, in run_endpoint_function
    return await dependant.call(**values)
  File "/usr/local/lib/python3.7/site-packages/boaviztapi/routers/component_router.py", line 28, in cpu_impact_bottom_up
    "verbose": verbose_component(completed_cpu, component_cpu, units=cpu.units or 1)}
  File "/usr/local/lib/python3.7/site-packages/boaviztapi/service/verbose.py", line 78, in verbose_component
    "value": rd.round_to_sigfig(*complete_component.impact_gwp()),
  File "/usr/local/lib/python3.7/site-packages/boaviztapi/model/components/component.py", line 85, in impact_gwp
    significant_figures=rd.min_significant_figures(self.die_size_per_core,core_impact,cpu_die_impact,cpu_impact)
  File "/usr/local/lib/python3.7/site-packages/boaviztapi/utils/roundit.py", line 20, in min_significant_figures
    sigfig = significant_number(inputs[0])
  File "/usr/local/lib/python3.7/site-packages/boaviztapi/utils/roundit.py", line 10, in significant_number
    int_part = int(abs(x))
TypeError: bad operand type for abs(): 'NoneType'

To Reproduce

Ask for CPU impact with those data :

"units": 1, "core_units": 24, "family": "Skylake", "manufacture_date": "2017",

Add : "die_size_per_core": 2.0

Then you get a valid answer.

Expected behavior

Sending an incomplete requests returns a 2xx with a message field that explains why there is no data to return or unsatisfying data.

Additional context

Trying the API through the server agent bootstrapped during hackathon # 4, but this is probably not relevant here.

bpetit commented 2 years ago

As a possible solution for this, we could use a data validation library, like one of those : https://www.yeahhub.com/7-best-python-libraries-validating-data/ to ensure required fields are provided and don't break the app if empty.

I've used voluptuous a bit, but any of those would probably do the job.

da-ekchajzer commented 2 years ago

The API should always send a valid answer independently of the completeness of the input value. In this case the API should retrieve a die_size _per_core of 0.289

This bug is due to an inversion of completed_cpu and component_cpu when calling verbose in component router. Verbose service try to access die_size of the uncomplete_component which is None.

I just pushed a fix in main branch and added a test that matches this specific case (incomplete CPU + verbose=true)