Package: py2http
Documentation herepy2httpDispatching Python functions as http services.You have some python objects and want to get an "equivalent" http service from them...UsageRun a basic HTTP service from a list of functions.frompy2http.serviceimportrun_app# Define or import functionsdefadd(a,b):returna+bdefmultiply(a,b):returna*bclassDivider:def__init__(self,dividend):self.dividend=dividenddefdivide(self,divisor):returnself.dividend/divisordivider_from_ten=Divider(10)# Make a list of functions or instance methodsfunc_list=[add,multiply,divider_from_ten.divide]# Create an HTTP serverrun_app(func_list,publish_openapi=True,publish_swagger=True)The HTTP server will listen on port 3030 by default.Given we asked for those options, you can:access the OpenAPI specification of the http-service athttp://localhost:3030/openapiaccess the swagger docs and fiddle of the http-service athttp://localhost:3030/swaggeractually use the http-service's routes, for example:# Test the server in a separate processimportrequestsurl='http://localhost:3030/add'add_args={'a':20,'b':22}requests.post(url,json=add_args).json()# should return 42Configurationrun_appaccept many configuration values to customize the handling of HTTP requests and responses. Configuration documentation is listed in the fileconfig.yaml.Method transformationExpose class methods by flattening the init -> method call process.frompy2httpimportrun_appfrompy2http.decoratorsimportmk_flatclassAdder:def__init__(self,a):self.a=adefadd(self,b):returnself.a+badd=mk_flat(Adder,Adder.add,func_name='add')func_list=[add]run_app(func_list)Input mappingBy default, the server will only accept JSON requests and parse the values from the request body as keyword arguments. You can define custom input mappers to perform extra handling on the JSON body or directly on the HTTP library request object, such as default injection or type mapping.fromnumpyimportarrayimportsoundfilefrompy2http.decoratorsimporthandle_json_reqfrommy_service.dataimportfetch_user_data@handle_json_req# extracts the JSON body and passes it to the input mapper as a dictdefarray_input_mapper(input_kwargs):return{'arr':array(input_kwargs.get('arr',[])),'scalar':input_kwargs.get('scalar',1)}@handle_multipart_req# extracts a multipart body and passes it as a dictdefsound_file_input_mapper(input_kwargs):file_input=input_kwargs['file_upload']filename=file_input.filenamefile_bytes=BytesIO(file_input.file)wf,sr=soundfile.read(file_bytes)returndict(input_kwargs,wf=wf,sr=sr,filename=filename)defcustom_header_input_mapper(req):# takes a raw aiohttp requestuser=req.headers.get('User','')return{'user':user}defarray_multiplier(arr,scalar):returnarr*scalardefsave_audio(wf,sr,filename,storage_path='/audio'):target=os.path.join(storage_path,filename)soundfile.write(target,wf,sr)defget_user_data(user):returnfetch_user_data(user)array_multiplier.input_mapper=array_input_mappersave_audio.input_mapper=sound_file_input_mapperget_user_data.input_mapper=custom_header_input_mapperOutput mappingBy default, the server will send the return value of the handler function in an HTTP response in JSON format. You can define custom output mappers to perform extra handling or type conversion.fromioimportBytesIOimportsoundfilefrompy2http.decoratorsimportsend_json_resp,send_html_respfrommy_service.dataimportfetch_blog@send_json_resp# sends a JSON responsedefarray_output_mapper(output,input_kwargs):return{'array_value':output['array_value'].tolist()}@send_html_resp# sends an HTML responsedefmk_html_list(output,input_kwargs):tag=input_kwargs.get('tag','p')item_list=output.split('\n')result=[f'<{tag}>{item}</{tag}>'foriteminitem_list]return''.join(result)defreturn_wav(output,input_kwargs):wf,sr=outputwf_bytes=BytesIO()soundfile.write(wf_bytes,wf,sr)binary_result=wf_bytes.read()returnweb.Response(body=binary_result,content_type='application/octet-stream')defarray_multiplier(arr,scalar):returnarr*scalardefget_blog_posts(page):returnfetch_blog(page)defdownload_audio(filename):withopen(filename)asfp:wf,sr=soundfile.read(fp)returnwf,srarray_multipler.output_mapper=array_output_mapperget_blog_posts.output_mapper=mk_html_listdownload_audio.output_mapper=return_wavError handlingTODOClient generationPy2http generates an OpenAPI specification for the server before running. You can use this document with any OpenAPI-compatible client tools. To extract the specification, you can generate a server application object before running it.importjsonfrompy2httpimportmk_app,run_appdefadd(a,b):returna+bfunc_list=[add]app=mk_app(func_list)openapi_spec=app.openapi_specwithopen('~/openapi.json','w')asfp:json.dump(openapi_spec,fp)run_app(app,port=3030)ConfigurationFunctions that generate an HTTP service, such asrun_app, accept a number of keyword arguments for configuration. The available configuration arguments are listed below with their defaults.framework=py2http.config.BOTTLEThe HTTP framework to use.input_mapper=py2http.default_configs.default_input_mapperA function to map an HTTP request to a dict of input arguments.output_mapper=py2http.default_configs.default_output_mapperA function to map the output of a function to an HTTP response.error_handler=py2http.default_configs.default_error_handlerA function to map an exception to an HTTP response.header_inputs={}A dict of object properties in JSON schema format describing keys that should be excluded from request body definitions. These inputs are expected to be extracted from the request headers in the input mapper.host='localhost'The hostname the server can be reached at, to include in the OpenAPI specification.port=3030The TCP port to listen on.http_method='post'The default HTTP method for exposing functions, if a function does not specify its method.openapi={}A dict with several configuration options specific to the OpenAPI specification, described below.logger=NoneAn object that implements alogmethod.app_name='HTTP Service'The name of the application (Flask only).middleware=[]A list of middlewares to run (aiohttp only).plugins=[]A list of plugins to install (bottle only).enable_cors=FalseWhether to enable CORS features.cors_allowed_origins='*'If CORS is enabled, the value to pass in the Access-Control-Allow-Origin header.publish_openapi=FalseWhether to add a GET /openapi route to the app that returns the OpenAPI specification.openapi_insecure=FalseWhether to skip middlewares and plugins for the /openapi route (disabling any authentication).publish_swagger=FalseWhether to add a GET route to the app that returns a Swagger HTML interface.swagger_url='/swagger'The URL of the swagger route.swagger_title='Swagger'The title to display on the Swagger HTML page.ssl_certfile=NoneThe path to a valid SSL certificate.ssl_keyfile=NoneThe path to a valid SSL certificate's key.OpenAPI configuration:These values will be put in the OpenAPI specification document. All values are optional.titleThe title of the application.versionThe version number of the application.auth: A dict specifying the authentication details to include in the document, to make it easier for clients to automate authentication.auth['auth_type']Either 'jwt' or 'api_key'.auth['login_details']A dict describing how a client can log in (for jwt authentication only).auth['login_details']['login_url']The URL of the login route.auth['login_details']['refresh_url']: The URL of the refresh route.auth['login_details']['login_inputs']: A list of strings with the keys expected by the login endpoint.auth['login_details']['refresh_inputs']: A list of strings with the keys expected by the refresh endpoint.auth['login_details']['outputs']: A list of strings with the keys returned by the login/refresh endpoints.,