class_docstr: HTTPApp creates a REST API server based on APIs defined with a BentoService
  via BentoService#apis. Each InferenceAPI will become one
  endpoint exposed on the REST server, and the RequestHandler defined on each
  InferenceAPI object will be used to handle Request object before feeding the
  request data into a Service API function
class_docstr_tok: ["HTTPApp","creates","a","REST","API","server","based","on","APIs","defined","with","a","BentoService","via","BentoService","#","apis",".","Each","InferenceAPI","will","become","one","endpoint","exposed","on","the","REST","server",",","and","the","RequestHandler","defined","on","each","InferenceAPI","object","will","be","used","to","handle","Request","object","before","feeding","the","request","data","into","a","Service","API","function"]
docstr: Create api function for starlette route, it wraps around user defined API
  callback and adapter class, and adds request logging and instrument metrics
docstr_tok: ["Create","api","function","for","starlette","route",",","it","wraps","around","user","defined","API","callback","and","adapter","class",",","and","adds","request","logging","and","instrument","metrics"]
code: def _create_api_endpoint(
      self,
      api: InferenceAPI[t.Any],
  ) -> t.Callable[[Request], t.Coroutine[t.Any, t.Any, Response]]:
      """
      Create api function for starlette route, it wraps around user defined API
      callback and adapter class, and adds request logging and instrument metrics
      """
      from starlette.concurrency import run_in_threadpool  # type: ignore
      from starlette.responses import JSONResponse
  
      from ..utils import is_async_callable
  
      async def api_func(request: Request) -> Response:
          # handle_request may raise 4xx or 5xx exception.
          output = None
          with self.bento_service.context.in_request(request) as ctx:
              try:
                  input_data = await api.input.from_http_request(
                      request
                  )
                  if api.multi_input:
                      if api.needs_ctx:
                          input_data[api.ctx_param] = ctx
                      if is_async_callable(api.func):
                          output = await api.func(**input_data)
                      else:
                          output = await run_in_threadpool(
                              api.func, **input_data
                          )
                  else:
                      args = (input_data,)
                      if api.needs_ctx:
                          args = (input_data, ctx)
                      if is_async_callable(api.func):
                          output = await api.func(*args)
                      else:
                          output = await run_in_threadpool(
                              api.func, *args
                          )
  
                  response = await api.output.to_http_response(
                      output, ctx if api.needs_ctx else None
                  )
  
              except BentoMLException as e:
                  log_exception(request, sys.exc_info())
                  if output is not None:
                      import inspect
  
                      signature = inspect.signature(api.output.to_proto)
                      param = next(iter(signature.parameters.values()))
                      ann = ""
                      if param is not inspect.Parameter.empty:
                          ann = param.annotation
  
                      # more descriptive errors if output is available
                      logger.error(
                          "Function '%s' has 'input=%s,output=%s' as IO descriptor, and returns 'result=%s', while expected return type is '%s'",
                          api.name,
                          api.input,
                          api.output,
                          type(output),
                          ann,
                      )
  
                  status = e.error_code.value
                  if 400 <= status < 500 and status not in (401, 403):
                      response = JSONResponse(
                          content="BentoService error handling API request: %s"
                          % str(e),
                          status_code=status,
                      )
                  else:
                      response = JSONResponse("", status_code=status)
              except Exception:  # pylint: disable=broad-except
                  # For all unexpected error, return 500 by default. For example,
                  # if users' model raises an error of division by zero.
                  log_exception(request, sys.exc_info())
  
                  response = JSONResponse(
                      "An error has occurred in BentoML user code when handling this request, find the error details in server logs",
                      status_code=500,
                  )
              if trace_context.request_id is not None:
                  response.headers["X-BentoML-Request-ID"] = str(
                      trace_context.request_id
                  )
              if (
                  BentoMLContainer.http.response.trace_id.get()
                  and trace_context.trace_id is not None
              ):
                  response.headers["X-BentoML-Trace-ID"] = str(
                      trace_context.trace_id
                  )
              return response
  
      return api_func
  
imports: from __future__ import annotations
  import asyncio
  import functools
  import logging
  import os
  import sys
  import typing
  from simple_di import Provide
  from simple_di import inject
  from starlette.exceptions import HTTPException
  from starlette.responses import PlainTextResponse
  from ...exceptions import BentoMLException
  from ..configuration.containers import BentoMLContainer
  from ..context import trace_context
  from ..server.base_app import BaseAppFactory
  from ..service.service import Service
label_desc: Use image node_id 8 for calling the HTTPAppFactory obj's underlying member method code with example usage: obj._create_api_endpoint(api) and returns: api_func, response