معرفی شرکت ها


asyncio-requests-2.7.3


Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر

توضیحات

Any microservice will be able to use the “asyncio_requests” can make an async request(HTTP/SOAP/XML/FTP/redis) with the given payload to given address
ویژگی مقدار
سیستم عامل -
نام فایل asyncio-requests-2.7.3
نام asyncio-requests
نسخه کتابخانه 2.7.3
نگهدارنده []
ایمیل نگهدارنده []
نویسنده Arjunsingh Yadav, Manish Magnani, Devesh Ratthour
ایمیل نویسنده arjunsinghyadav@fynd.com, manishmagnani@gofynd.com
آدرس صفحه اصلی https://github.com/gofynd/asyncio-requests
آدرس اینترنتی https://pypi.org/project/asyncio-requests/
مجوز MIT
# Async HTTP / SOAP / FTP Request Library This library provides the functionality to make async API calls via HTTP / SOAP / FTP protocols via a config. ### Installation ```pip install asyncio-requests ``` ## HTTP * Uses aiohttp internally * Has an inbuilt circuit breaker * Currently supports infinite nested depth of pre and post processors * Retry Functionality * Exceptions can be contributed in the utilities, and you can use your own exceptions in the circuit breaker config as well. * Direct File Upload functionality. Params - <table> <tbody> <tr> <th class="Title" align="center">Param</th> <th class="Title" align="center">Data Type</th> <th class="Title" align="center">Optional/Required</th> <th class="Title" align="center">Help</th> </tr> <tr> <td align="center">url</td> <td align="center">Str</td> <td align="center">Required</td> <td align="center">URL to be hit</td> </tr> <tr> <td align="center">data</td> <td align="center">Dict</td> <td align="center">Optional</td> <td align="center">data to be sent. It can be dict or str. If dict, it will be dumped via ujson.dumps method</td> </tr> <tr> <td align="center">auth</td> <td align="center">auth object</td> <td align="center">Optional</td> <td align="center">Auth param is expected to be an auth object of your choice which is accepted by aiohttp. Eg - aiohttp.BasicAuth(username, password)</td> </tr> <tr> <td align="center">protocol</td> <td align="center">Str</td> <td align="center">Required</td> <td align="center">(HTTP/HTTPS/SOAP/FTP)</td> </tr> <tr> <td align="center">pre_processor_config</td> <td align="center">Dict</td> <td align="center">Optional</td> <td> <ul> <li>pre processor indicates an action (file download/api call or anything) to be done before making the actual API call.</li> <li>Takes async callable object which is executed before making the actual API call - Required</li> <li>Params dictionary where key is parameter to the callable object passed in pre processor and values is parameter value</li> <li>The callable object/function can be used from the utilities folder which is contributed by all or your own function address.</li> <li>You can nest the whole API. Eg - you can pass the address of asyncio_requests.request function too. The response will be a nested one. (Explained via example down)</li> </ul> </td> </tr> <tr> <td align="center">post_processor_config</td> <td align="center">Dict</td> <td align="center">Optional</td> <td> <ul> <li>post processor indicates an action (file download or delete file or api call or anything) to be done post making the actual API call.</li> <li>function: Takes async callable object/function address which is executed after making request - Required</li> <li>Params: Takes dictionary where key is parameter to the callable object/function passed in pre-processor and values is parameter value</li> <li>similar to pre-processor, difference being this is executed after making an API call.</li> <li>Eg - if you want to send the data of a file in the API call and the file needs to be downloaded. You can have a file download pre-processor function and have a file deletion post processor function.</li> </ul> </td> </tr> <tr aria-rowspan="12"> <td align="center">protocol_info</td> <td align="center">Dict</td> <td align="center">Required</td> <td> <ul> <li>request_type - Str. Required. GET/PUT/POST/PATCH/DELETE/OPTIONS</li> <li>timeout - Int. Optional. Default HTTP timeout is 15 seconds. Can be overridden if specified.</li> <li>certificate - Tuple(str, str) Optional. Used for SSL certificates and expected in the format Tuple('certificate path', 'certificate key path')</li> <li>verify_ssl - Boolean. Optional. SSL is enabled by default</li> <li>cookies - Str. Optional</li> <li>headers - Dict. Required</li> <li>trace_config - List[tracer_callable_object] Optional. default tracer is aiohttp.TraceConfig() - Optional</li> <li> http_file_upload_config: Dict use this only if you want to send file in request. If you use this config then only file will be sent in request - Optional <ul> <li>local_filepath: machine file path for file to be sent in request</li> <li>file_key: The key in which the file data is to be sent</li> </ul> </li>serialization: serializer callable object. Optional. If you want to use any json serializer then you can pass here default is ujson.dumps.</li> <li>circuit_breaker_config - Dict - Optional <ul> <li>maximum_failures - Int. Optional. maximum failures you want to allow for request default is 5</li> <li>timeout - Int Optional. seconds timeout you want to keep for request default is 60 seconds</li> <li>retry_config - Dict - Optional <ul> <li>name - Str required</li> <li>allowed_retries - Int. Required this is for how many retries you want to perform</li> <li>retriable_exceptions - List[<callable object of exception>]. Optional. list of exception types indicating which exceptions can cause a retry. If None every exception is considered retriable</li> <li>abortable_exceptions - List[<callable object of exception>]. Optional. list of exception types indicating which exceptions should abort failsafe run immediately and be propagated out of failsafe. If None, no exception is considered abortable.</li> <li>on_retries_exhausted - callable object. Optional. callable/function_address which will be invoked on retry exhausted event</li> <li>on_failed_attempt - callable object. Optional. callable/function_address that will be invoked on a failed attempt event</li> <li>on_abort - callable object. Optional. callable that will be invoked on an abort event</li> <li>delay - Int Optional. seconds of delay between retries default is 0.</li> <li>max_delay - Int Optional. seconds of max delay between retries default 0</li> <li>jitter: Boolean Optional. False when you want to keep the wait between calls constant else True</li> </ul> </li> </ul> </li> </ul> </td> </tr> </tbody> </table> Defaults - * By default, circuit breaker is not enabled and is activated only if provided with its config. * By default, retry is not enabled and is activated only if provided with its config. * Default Request tracer is enabled which provides the traces of the whole request wrt data chunks, dns cache hit etc. * In case of user specific request tracer, a list of request tracer objects is expected which will override the default tracer. * Default serialization is via ujson and can be overwritten by specifying one * SSL is enabled by default ### How to Use * Design the http request payload as per below format * Mock url - https://api.fyndx1.de/masquerader/v1/aio-request-test/post is live and open for use. ```python import aiohttp from asyncio_requests.asyncio_request import request await request( url="URL FOR REQUEST", # str <Required> data={ "key": "val" } or "", # Data to be sent in body as dict or str, auth=aiohttp.BasicAuth('username', 'password'), # This auth object is to be made by the user itself as there are n number of # auth mechanisms to add to. Eg - auth=aiohttp.BasicAuth(username, password). Its an Optional field. protocol="REQUEST PROTOCOL", # str <Required> (HTTP/HTTPS) protocol_info={ "request_type": "GET", # str <Required> "timeout": 15, # int <Optional> Default - 15 "certificate": ('', ''), # Tuple(str, str) <Optional>, "verify_ssl": True, # Boolean <Optional>, "cookies": "", # str <Optional>, "headers": {}, # dict <Optional>, "http_file_upload_config": { # optional Include only if you want call api with file. If this is included api body will have only file "local_filepath": "required", # File path to be sent "file_key": "required", # File to be sent on which key in request body "file_upload_chunk_size": "optional" # size of stream if streaming upload is required # After making API if you want to delete file then add value as True default is false. }, "http_file_download_config": { "download_filepath": "required" # In case file downloads, location to which file is stored "file_download_chunk_size": "optional" # chunk size of a stream. } "circuit_breaker_config": { # Optional "maximum_failures": int, # Optional Failures allowed "timeout": int, # Optional time in seconds "retry_config": { # Optional Include this if you want retry API calls if failed on first time "name": str, # Required Any name "allowed_retries": int, # Required number of retries you want to make "retriable_exceptions": [<callable object>] # Optional "abortable_exceptions": [<callable object>] # Optional "on_retries_exhausted": <callable object>, # Optional callable that will be invoked on a retries exhausted event, "on_failed_attempt": <callable object>, # Optional callable that will be invoked on a failed attempt event, "on_abort": <callable object>, # Optional callable that will be invoked on an abort event, "delay": int, # seconds of delay between retries Optional default 0, "max_delay": int, # seconds of max delay between retries Optional default 0, "jitter": bool # Boolean Optional, } } }, pre_processor_config = { # Optional "function": <callable object>, # Required function that you want to call before http call "params": { # Optional "param1": "value1" # Params you want to pass in function } }, post_processor_config = { # Optional "function": <callable object>, # Required function that you want to call after http call "params": { "param1": "value1" # Params you want to pass in function } } ) ``` * **Basic HTTP POST call** ```python from asyncio_requests.asyncio_request import request result = await request( url="https://api.fyndx1.de/masquerader/v1/aio-request-test/post", data={ "first_name": "Joy", "last_name": "Pandey", "gender": "M" }, protocol="HTTPS", protocol_info={ "request_type": "POST" } ) ### Response """ { 'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post', 'payload': { 'first_name': 'Joy', 'last_name': 'Pandey', 'gender': 'M' }, 'external_call_request_time': '2022-02-17 17:25:03.930531+05:30', 'text': '', 'error_message': '', 'api_response': { 'status_code': 200, 'headers': { 'Date': 'Thu, 17 Feb 2022 11:55:04 GMT', 'Content-Type': 'application/json', 'Content-Length': '57', 'Connection': 'keep-alive', 'X-Fynd-Trace-Id': '78ca02ff444ae5855e856c5f3d769364' }, 'cookies': { }, 'content': b'{"method": "POST", "status": true, "error_message": null}', 'text': '{"method": "POST", "status": true, "error_message": null}', 'json': { 'method': 'POST', 'status': True, 'error_message': None }, 'request_tracer': [ { 'on_request_start': 287753.868594354, 'is_redirect': False, 'on_connection_create_start': 0.0002811980084516108, 'on_dns_cache_miss': 0.002910615992732346, 'on_dns_resolvehost_start': 0.0029266909696161747, 'on_dns_resolvehost_end': 0.04894679499557242, 'on_connection_create_end': 0.15098483895417303, 'on_request_chunk_sent': 0.15202936198329553, 'on_request_end': 0.2799108889885247 } ] } } """ ``` * **API call with circuit breaker and custom exceptions** ```python from asyncio_requests.asyncio_request import request class HTTPRequestFailedException(Exception): pass class CustomException(Exception): pass def retry_exhausted_actions(): print("All retries exhausted. API call failed.") def request_attempt_failed_actions(): print("API call failed.") def request_abort_actions(): print("API call aborted") result = await request( url="https://api.fyndx1.de/masquerader/v1/aio-request-test/post", data={ "first_name": "Joy", "last_name": "Pandey", "gender": "M" }, protocol="HTTPS", protocol_info={ "request_type": "POST", "circuit_breaker_config": { "maximum_failures": 5, "timeout": 15, "retry_config": { "name": "retry_masquerader", "allowed_retries": 5, "retriable_exceptions": [HTTPRequestFailedException], "abortable_exceptions": [CustomException], "on_retries_exhausted": retry_exhausted_actions, "on_failed_attempt": request_attempt_failed_actions, "on_abort": request_abort_actions, "delay": 5, "max_delay": 300, "jitter": True } } } ) ### Value of result """ { 'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post', 'payload': { 'first_name': 'Joy', 'last_name': 'Pandey', 'gender': 'M' }, 'external_call_request_time': '2022-02-18 12:57:20.762713+05:30', 'text': '', 'error_message': '', 'api_response': { 'status_code': 200, 'headers': { 'Date': 'Fri, 18 Feb 2022 07:27:21 GMT', 'Content-Type': 'application/json', 'Content-Length': '57', 'Connection': 'keep-alive', 'X-Fynd-Trace-Id': '390cd5e9f4b1f179d5d711ca7bc83ec3' }, 'cookies': { }, 'content': b'{"method": "POST", "status": true, "error_message": null}', 'text': '{"method": "POST", "status": true, "error_message": null}', 'json': { 'method': 'POST', 'status': True, 'error_message': None }, 'request_tracer': [ { 'on_request_start': 352622.180567606, 'is_redirect': False, 'on_connection_create_start': 0.0009668020065873861, 'on_dns_cache_miss': 0.07304156001191586, 'on_dns_resolvehost_start': 0.07307461701566353, 'on_dns_resolvehost_end': 0.31564718199661, 'on_connection_create_end': 0.5526716759777628, 'on_request_chunk_sent': 0.5531467269756831, 'on_request_end': 0.6851100819767453 } ] } } """ ``` * **API with pre and post processor enabled with circuit breaker and retries.** ```python from asyncio_requests.asyncio_request import request from typing import Dict, Text async def make_request_payload(response: Dict, first_name: Text, last_name: Text, gender: Text): response["payload"] = { "first_name": first_name, "last_name": last_name, "gender": gender } async def print_response_recieved_from_api(response: Dict, text: Text): print(f"{text}{response['api_response']}") result = await request( url="https://api.fyndx1.de/masquerader/v1/aio-request-test/post", protocol="HTTPS", protocol_info={ "request_type": "POST", "circuit_breaker_config": { "timeout": 150, "retry_config": { "name": "api_retry", "allowed_retries": 4 } } }, pre_processor_config={ "function": make_request_payload, "params": { "first_name": "Joy", "last_name": "Pandey", "gender": "M" } }, post_processor_config={ "function": print_response_recieved_from_api, "params": { "text": "Response received from API: " } } ) ### Response ### The pre and post processor keys have no values in response since they were just print statements. Had they been API calls, the value would have been different. ### The print statements will be printed in the shell if run but won't have its resemblence in the response. """ { 'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post', 'payload': { 'first_name': 'Joy', 'last_name': 'Pandey', 'gender': 'M' }, 'external_call_request_time': '2022-02-17 17:33:35.508376+05:30', 'text': '', 'error_message': '', 'pre_processor_response': None, 'api_response': { 'status_code': 200, 'headers': { 'Date': 'Thu, 17 Feb 2022 12:03:35 GMT', 'Content-Type': 'application/json', 'Content-Length': '57', 'Connection': 'keep-alive', 'X-Fynd-Trace-Id': '8903eeb30ed218385631d3b52d04b38e' }, 'cookies': { }, 'content': b'{"method": "POST", "status": true, "error_message": null}', 'text': '{"method": "POST", "status": true, "error_message": null}', 'json': { 'method': 'POST', 'status': True, 'error_message': None }, 'request_tracer': [ { 'on_request_start': 288265.446420053, 'is_redirect': False, 'on_connection_create_start': 0.00028238497907295823, 'on_dns_cache_miss': 0.0028724189614877105, 'on_dns_resolvehost_start': 0.002888173970859498, 'on_dns_resolvehost_end': 0.09302646096330136, 'on_connection_create_end': 0.2075990799930878, 'on_request_chunk_sent': 0.20890663599129766, 'on_request_end': 0.319920428970363 } ] }, 'post_processor_response': None } """ ``` * **Having separate API call in pre-processor.** * This is usually the case wherein we want to report some data before making the actual API call ```python from asyncio_requests.asyncio_request import request result = await request( url="https://api.fyndx1.de/masquerader/v1/aio-request-test/post", data={ "first_name": "Joy", "last_name": "Pandey", "gender": "M" }, protocol="HTTPS", protocol_info={ "request_type": "POST" }, pre_processor_config={ "function": request, "async_enabled": True, "params": { "url": "https://api.fyndx1.de/masquerader/v1/aio-request-test/post", "data": { "first_name": "Joy", "last_name": "Pandey", "Gender": "M" }, "protocol": "HTTP", "protocol_info": { "request_type": "POST" } } } ) ### Value of result """ { 'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post', 'payload': { 'first_name': 'Joy', 'last_name': 'Pandey', 'gender': 'M' }, 'external_call_request_time': '2022-02-18 13:26:35.575362+05:30', 'text': '', 'error_message': '', 'pre_processor_response': { 'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post', 'payload': { 'first_name': 'Joy', 'last_name': 'Pandey', 'Gender': 'M' }, 'external_call_request_time': '2022-02-18 13:26:35.575469+05:30', 'text': '', 'error_message': '', 'api_response': { 'status_code': 200, 'headers': { 'Date': 'Fri, 18 Feb 2022 07:56:36 GMT', 'Content-Type': 'application/json', 'Content-Length': '57', 'Connection': 'keep-alive', 'X-Fynd-Trace-Id': 'ae2703a4c82e8f917c53faded0688717' }, 'cookies': {}, 'content': b'{"method": "POST", "status": true, "error_message": null}', 'text': '{"method": "POST", "status": true, "error_message": null}', 'json': { 'method': 'POST', 'status': True, 'error_message': None }, 'request_tracer': [ { 'on_request_start': 354376.993160197, 'is_redirect': False, 'on_connection_create_start': 0.00041024398524314165, 'on_dns_cache_miss': 0.004407248983625323, 'on_dns_resolvehost_start': 0.0044287089840509, 'on_dns_resolvehost_end': 0.32443026901455596, 'on_connection_create_end': 0.44923901598667726, 'on_request_chunk_sent': 0.449799319030717, 'on_request_end': 0.5300842020078562 } ] } }, 'api_response': { 'status_code': 200, 'headers': { 'Date': 'Fri, 18 Feb 2022 07:56:36 GMT', 'Content-Type': 'application/json', 'Content-Length': '57', 'Connection': 'keep-alive', 'X-Fynd-Trace-Id': 'ddb370fbf58999c359fe384b547446c9' }, 'cookies': {}, 'content': b'{"method": "POST", "status": true, "error_message": null}', 'text': '{"method": "POST", "status": true, "error_message": null}', 'json': { 'method': 'POST', 'status': True, 'error_message': None }, 'request_tracer': [ { 'on_request_start': 354377.524928869, 'is_redirect': False, 'on_connection_create_start': 0.000421632023062557, 'on_dns_cache_miss': 0.00067474803654477, 'on_dns_resolvehost_start': 0.0006999420002102852, 'on_dns_resolvehost_end': 0.002583371999207884, 'on_connection_create_end': 0.09995210904162377, 'on_request_chunk_sent': 0.10060718702152371, 'on_request_end': 0.2261603070073761 } ] } } """ ``` * **API call with nested pre and post processors** * Here the pre processor(parent) has another pre-processor(child) within it. * The response will include all the nested responses in the same fashion as that of the config set * The actual flow would be (child pre-processor -> parent pre-processor -> main API call -> parent post-processor -> child post processor) * response format will be this way - ``` parent pre-processor response child pre processor response child's child pre preprocesor response infinite nesting... main api call response parent post-processor response child post processor response child's child post preprocesor response infinite nesting... ``` ```python from asyncio_requests.asyncio_request import request async def test_fun(*args, **kwargs): return {"text": "final res"} result = await request( url="https://api.fyndx1.de/masquerader/v1/aio-request-test/post", data={ "first_name": "Joy", "last_name": "Pandey", "Gender": "M" }, protocol="HTTP", protocol_info={ "request_type": "POST", "circuit_breaker_config": { "timeout": 150, "retry_config": { "name": "asdf", "allowed_retries": 1 } } }, pre_processor_config={ "function": request, "async_enabled": True, "params": { "url": "https://api.fyndx1.de/masquerader/v1/aio-request-test/post", "data": { "first_name": "Joy", "last_name": "Pandey", "Gender": "M" }, "protocol": "HTTP", "protocol_info": { "request_type": "POST", "circuit_breaker_config": { "retry_config": { "name": "asdf", "allowed_retries": 5 } }, }, "pre_processor_config": { "function": test_fun, "async_enabled": True, "params": { "url": "https://api.fyndx1.de/masquerader/v1/aio-request-test/post", "data": { "first_name": "Joy", "last_name": "Pandey", "Gender": "M" }, "protocol": "HTTP", "protocol_info": { "request_type": "POST", "circuit_breaker_config": { "retry_config": { "name": "asdf", "allowed_retries": 5 } }, } } } } }, post_processor_config={ "function": request, "async_enabled": True, "params": { "url": "https://api.fyndx1.de/masquerader/v1/aio-request-test/post", "data": { "first_name": "Joy", "last_name": "Pandey", "Gender": "M" }, "protocol": "HTTP", "protocol_info": { "request_type": "POST", "circuit_breaker_config": { "retry_config": { "name": "asdf", "allowed_retries": 5 } }, }, "post_processor_config": { "function": test_fun, "async_enabled": True, "params": { "url": "https://api.fyndx1.de/masquerader/v1/aio-request-test/post", "data": { "first_name": "Joy", "last_name": "Pandey", "Gender": "M" }, "protocol": "HTTP", "protocol_info": { "request_type": "POST", "circuit_breaker_config": { "retry_config": { "name": "asdf", "allowed_retries": 5 } }, } } } } } ) ### Response """ { 'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post', 'payload': { 'first_name': 'Joy', 'last_name': 'Pandey', 'Gender': 'M' }, 'external_call_request_time': '2022-02-17 17:22:01.383304+05:30', 'text': '', 'error_message': '', 'pre_processor_response': { 'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post', 'payload': { 'first_name': 'Joy', 'last_name': 'Pandey', 'Gender': 'M' }, 'external_call_request_time': '2022-02-17 17:22:01.383358+05:30', 'text': '', 'error_message': '', 'pre_processor_response': { 'text': 'final res' }, 'api_response': { 'status_code': 200, 'headers': { 'Date': 'Thu, 17 Feb 2022 11:52:01 GMT', 'Content-Type': 'application/json', 'Content-Length': '57', 'Connection': 'keep-alive', 'X-Fynd-Trace-Id': 'b1a3111270067ae160eeaf9971b04cc5' }, 'cookies': { }, 'content': b'{"method": "POST", "status": true, "error_message": null}', 'text': '{"method": "POST", "status": true, "error_message": null}', 'json': { 'method': 'POST', 'status': True, 'error_message': None }, 'request_tracer': [ { 'on_request_start': 287571.321608293, 'is_redirect': False, 'on_connection_create_start': 0.00031328899785876274, 'on_dns_cache_miss': 0.0029667950002476573, 'on_dns_resolvehost_start': 0.0029829980339854956, 'on_dns_resolvehost_end': 0.0064852479845285416, 'on_connection_create_end': 0.08529951400123537, 'on_request_chunk_sent': 0.0858444279874675, 'on_request_end': 0.1671372150303796 } ] } }, 'api_response': { 'status_code': 200, 'headers': { 'Date': 'Thu, 17 Feb 2022 11:52:01 GMT', 'Content-Type': 'application/json', 'Content-Length': '57', 'Connection': 'keep-alive', 'X-Fynd-Trace-Id': '3340481533a6511b15952cabb4c144bb' }, 'cookies': { }, 'content': b'{"method": "POST", "status": true, "error_message": null}', 'text': '{"method": "POST", "status": true, "error_message": null}', 'json': { 'method': 'POST', 'status': True, 'error_message': None }, 'request_tracer': [ { 'on_request_start': 287571.490459029, 'is_redirect': False, 'on_connection_create_start': 0.0006432340014725924, 'on_dns_cache_miss': 0.00104641099460423, 'on_dns_resolvehost_start': 0.001091104990337044, 'on_dns_resolvehost_end': 0.0037200640072114766, 'on_connection_create_end': 0.10335264401510358, 'on_request_chunk_sent': 0.10410607699304819, 'on_request_end': 0.18950222100829706 } ] }, 'post_processor_response': { 'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post', 'payload': { 'first_name': 'Joy', 'last_name': 'Pandey', 'Gender': 'M' }, 'external_call_request_time': '2022-02-17 17:22:01.743288+05:30', 'text': '', 'error_message': '', 'api_response': { 'status_code': 200, 'headers': { 'Date': 'Thu, 17 Feb 2022 11:52:02 GMT', 'Content-Type': 'application/json', 'Content-Length': '57', 'Connection': 'keep-alive', 'X-Fynd-Trace-Id': 'a0304896aabbc394894d442fa27a5c3e' }, 'cookies': { }, 'content': b'{"method": "POST", "status": true, "error_message": null}', 'text': '{"method": "POST", "status": true, "error_message": null}', 'json': { 'method': 'POST', 'status': True, 'error_message': None }, 'request_tracer': [ { 'on_request_start': 287571.681455504, 'is_redirect': False, 'on_connection_create_start': 0.00041248503839597106, 'on_dns_cache_miss': 0.0006613450241275132, 'on_dns_resolvehost_start': 0.0006853759987279773, 'on_dns_resolvehost_end': 0.0024919320130720735, 'on_connection_create_end': 0.08381915499921888, 'on_request_chunk_sent': 0.08448734600096941, 'on_request_end': 0.5899507160065696 } ] }, 'post_processor_response': { 'text': 'final res' } } } """ ``` * **API call to send a file** * Here we are downloading a file in the pre-processor. If the file is already present in the system then you can avoid that pre-processor and directly mention the file address in the local_file_path variable. * The file can be downloaded by using the existing pre processor function in the utilities. * The Utilities dir has a function that supports file download via url/aws s3. * The Utilities dir also has a function to delete a file. If you want to delete teh file post making the API call, use this in the post processor. * If you have some other way around to download the file, just pass that function address in the pre processor and include the file address in the local_file_path variable. ```python from asyncio_requests.asyncio_request import request from asyncio_requests.utils.http_file_upload_config import download_file_from_url, delete_local_file_path local_file_path = "/tmp/test.pdf" result = await request( url="http://localhost:5000/api/v1/test/aio-request-files", protocol="HTTPS", protocol_info={ "request_type": "POST", "http_file_upload_config": { "local_filepath": local_file_path, "file_key": "file" } }, pre_processor_config={ "function": download_file_from_url, "params": { "file_download_path": "https://didukhn.github.io/homepage/assets/img/photo.jpg", "local_filepath": local_file_path } }, post_processor_config={ "function": delete_local_file_path, "params": { "local_filepath": local_file_path } } ) ### Response """ { 'url': 'http://localhost:5000/api/v1/test/aio-request-files', 'payload': { }, 'external_call_request_time': '2022-02-17 17:13:03.231826+05:30', 'text': '', 'error_message': '', 'pre_processor_response': None, 'api_response': { 'status_code': 200, 'headers': { 'Connection': 'close', 'Content-Length': '29', 'Content-Type': 'application/json' }, 'cookies': { }, 'content': b'{"success":true,"message":""}', 'text': '{"success":true,"message":""}', 'json': { 'success': True, 'message': '' }, 'request_tracer': [ { 'on_request_start': 287033.4935145, 'is_redirect': False, 'on_connection_create_start': 0.0021707930136471987, 'on_dns_cache_miss': 0.002449413004796952, 'on_dns_resolvehost_start': 0.002480961033143103, 'on_dns_resolvehost_end': 0.003233974042814225, 'on_connection_create_end': 0.0042467640014365315, 'on_request_chunk_sent': 0.0064254660392180085, 'on_request_end': 0.1773580180015415 } ] }, 'post_processor_response': None } """ ``` **Utilities Included** * Download a file from AWS S3 * Download a file from public url * Delete a local file on system ## FTP * Uses aioftp internally to implement FTP/FTPS. * Added functionality of circuit breaker, pre and post processor configs same as http. * Can Leverage all the ftp commands provided by aioftp library. * By Default used FTP protocol can use FTPS if ssl config is enabled. # How to use. ```python import aiohttp from asyncio_requests.asyncio_request import request await request( url="Server Ip", # Ip/url or ftp server <Required> auth=aiohttp.BasicAuth('username', 'password'), # The username and ip of the ftp server, to be sent as aiohttp.BasicAuth object <Required> protocol="FTP", # str <Required> (FTP) protocol_info={ "port": 21, # default is 21 <Optional> "command": "download", # generic ftp commands like download, upload, remove <Required> "server_path": "/tmp/temp.pdf", # path from where to get/remove or upload file on server. "client_path": "", # path where file is downloaded/uploaded to. <optional> "timeout": 30 # <Optional> "verify_ssl": False # default is False <Optional> "certificate" "" # required if verify_ssl is True "circuit_breaker_config": { # Optional "maximum_failures": int, # Optional Failures allowed "timeout": int, # Optional time in seconds "retry_config": { # Optional Include this if you want retry calls if failed on first time "name": str, # Required Any name "allowed_retries": int, # Required number of retries you want to make "retriable_exceptions": [<callable object>] # Optional "abortable_exceptions": [<callable object>] # Optional "on_retries_exhausted": <callable object>, # Optional callable that will be invoked on a retries exhausted event, "on_failed_attempt": <callable object>, # Optional callable that will be invoked on a failed attempt event, "on_abort": <callable object>, # Optional callable that will be invoked on an abort event, "delay": int, # seconds of delay between retries Optional default 0, "max_delay": int, # seconds of max delay between retries Optional default 0, "jitter": bool # Boolean Optional, } } }, pre_processor_config = { # Optional "function": <callable object>, # Required function that you want to call before ftp call "params": { # Optional "param1": "value1" # Params you want to pass in function } }, post_processor_config = { # Optional "function": <callable object>, # Required function that you want to call after ftp call "params": { "param1": "value1" # Params you want to pass in function } } ) ``` # Sample FTP Call. ```python import aiohttp from asyncio_requests.asyncio_request import request from asyncio_requests.utils.http_file_upload_config import download_file_from_url local_path = "/tmp/temp.png" await request( url = "localhost", auth = aiohttp.BasicAuth("use","pswd"), protocol = "FTP", protocol_info = { "port": 21, "command": "upload", "server_path": "/home/resources/logo.png", "client_path": local_path, "circuit_breaker_config": { "timeout": 150, "retry_config": { "name": "api_retry", "allowed_retries": 4 } } }, pre_processor_config = { "function": download_file_from_s3, "params": { "file_download_path": "https://[bucket_name].s3.amazonaws.com/logo.png", "local_filepath": local_path } } ) ## Resonse """ {'api_response': True, 'error_message': '', 'external_call_request_time': '2022-05-13 19:07:35.775706+05:30', 'file': '/home/resources/logo.png', 'file_stats': {'modify': '20220513190700', 'size': '29304', 'type': 'file', 'unix.group': '1000', 'unix.links': '1', 'unix.mode': 436, 'unix.owner': '1000'}, 'mode': 'upload', 'payload': {'success': True}, 'pre_processor_response': None, 'text': '', 'url': 'localhost'} """ ``` ## SOAP (upcoming) ### Generating Distribution Archives ```bash python3 -m pip install --upgrade setuptools wheel python3 setup.py sdist bdist_wheel ``` This command should output a lot of text and once completed should generate two files in the `dist` directory. ## Open Source contribution You can add utilities that can be used by others. Eg - Contributing a function that accepts certain params and downloads a file via AWS S3. This function can be used by other developers in the pre/post processor to download the file before or after making the API call. **Make sure to add the utility in the utilities section in the readme wrt protocol.** ### Generating New Tags/Release - Check the code with flake8, mypy, bandit, pytest before submitting a PR - Update version in [setup.py](setup.py) - Update version in [docs/source/conf.py](docs/source/conf.py) - Update version in README.md section - Send a PR, and after it gets merged to master create a tag from master in the format `vX.Y` - `X` - Major Release (Breaking Changes) - `Y` - Minor Release **To know more about the developer, here's a quote to find him out -** ```Anton died so we could live```


نحوه نصب


نصب پکیج whl asyncio-requests-2.7.3:

    pip install asyncio-requests-2.7.3.whl


نصب پکیج tar.gz asyncio-requests-2.7.3:

    pip install asyncio-requests-2.7.3.tar.gz