Stop propogation of request to next middleware if response returned from first middleware in FastApi - fastapi

I am working on a problem where in I am creating a middleware that responds to one api and if that api is different then we go to next middleware else we exit out from the first middleware.
Maybe I have not understood how middleware works in FastApi but my code is not working so any assistance will be welcomed.
My code is as below
#app.middleware("http")
async def verify_user_agent(request: Request, call_next):
if request.url.path == "/something" and request.method == "GET":
return JSONResponse(content={"Something": True}, status_code=200)
else:
await call_next(request)
return JSONResponse(content={
"message": "redirecting to api middleware"
}, status_code=307)
# This middleware should be hit only if route is not /something
#app.middleware("http")
async def api_route(request: Request, call_back):
if request.url.path == "/api":
return JSONResponse(content={"api": True}, status_code=200)
return JSONResponse(content={"api": False})
Here even if the first route called is /something still the second middleware is called even though the response is already sent by the first middleware
If you need any more information then please do lemme know

So I think you have understood middleware just fine, however there is just one thing you are missing and that is in relation to the precedence of your middleware. Precedence can be determined by the order of your middleware and FastApi will register your middleware in the reverse order that they are defined in. This means in your example the first middleware in line is the one that checks for the /api route, which means it never gets to the /something check. all you need to do is swap them around.
# This middleware will be called second
#app.middleware("http")
async def api_route(request: Request, call_back):
if request.url.path == "/api":
return JSONResponse(content={"api": True}, status_code=200)
return JSONResponse(content={"api": False})
# this middleware will be called first
#app.middleware("http")
async def verify_user_agent(request: Request, call_next):
if request.url.path == "/something" and request.method == "GET":
return JSONResponse(content={"Something": True}, status_code=200)
else:
await call_next(request)
return JSONResponse(content={
"message": "redirecting to api middleware"
}, status_code=307)

Related

How to make a node.js Asynchronous API call and use a returned value?

It seems like has been asked a 1000 times but in reading all of the responses I still cannot seem to figure out how to make this work.
Here is my use case.
Make a call to an Auth Endpoint and return an access token
do some updates to the options of a 2nd API call
make the next api call with the updated options
I know how to make this work with traditional promises or callbacks but in my case step 1 & 2 could be optional so what I want to do is if step 1 & 2 are required call an async function to get the token and update the options. If 1 & 2 are not required then just make the 2nd API call.
I am trying to use axios but no matter what I do the response is either undefined or
Here is my code, can someone please explain the best way to do this, or is it just easier to use traditional promise\callbacks?
var options = {
'method': httpVerb ,
'url': url,
'headers': {
'Content-Type': 'application/json'
},
body: JSON.stringify(bodyArgs)
};
if(authBody){
auth = getAuth(authBody)
options.headers["Authorization"] = "Bearer " + auth.access_token;
console.log(auth)
}
const getAuth = async (options) => {
try{
const resp = await axios.post(options.authURL, options )
if(resp.status === 200){
return resp.data;
}else{
return ""
}
}catch(err){
console.error(err);
}
}
auth = getAuth(authBody) // wrong
getAuth is an async function, and async functions always return Promises even if the return statements within them return simple values.
If you want to wait for the return value of getAuth, you're going to have to do so in a then function on the return value, or await the result from within a different async function. Consequently, if you have an optional asynchronous step, it is safer to make the whole process appear asynchronous to abstract away the cases where you need to wait to refresh the token.

Can Google Apps Script handle HTTP DELETE requests?

It handles GET and POST requests just fine, via the respective doGet() & doPost() request handler functions. But what about DELETE requests? Is there some kind of implementation of a doDelete() function? My particular use case requires that I can send and receive a response from a DELETE request, in addition to POST and GET.
According to https://developers.google.com/apps-script/guides/web there is no doDelete or something similar, only doPost and doGet.
According to docs DELETE request works fine.
This is how I use it in my project
const params = {
"method": "DELETE",
"headers": this.getAuthHeader(),
"payload": JSON.stringify(payload)
};
const responseString = UrlFetchApp.fetch(this.getBaseUrl() + url, params);
if (responseString.getResponseCode() === 200) {
return JSON.parse(responseString);
}

FastAPI as backend for Telethon

I'm trying to make api auth with telethon work. I'm sending request to endpoint where telegram client is initialized and trying to send code request to telegram. But there is input() and I didn't find any solution to pass code as variable
#router.get('/code')
async def send_code_request(phone: str):
client = get_telegram_client(phone)
await client.start(phone)
return {'msg': 'code sent'}
I found easier solution, but there is one con - when authorizing via session sign_in() method is requiring to execute send_code_request() method first so there is will be 2 same code messages
async def get_telegram_client(session: str = None) -> TelegramClient:
return TelegramClient(
StringSession(session),
api_id=settings.TELEGRAM_API_ID,
api_hash=settings.TELEGRAM_API_HASH
)
#router.post('/code')
async def send_authorizarion_code(payload: TelegramSendCode):
client = await get_telegram_client()
await client.connect()
try:
await client.send_code_request(payload.phone)
except FloodWaitError as e:
return {
'FloodWaitError': {
'phone_number': e.request.phone_number,
'seconds': e.seconds
}}
else:
return {
'msg': 'code sent',
'session': client.session.save()
}
#router.post('/auth')
async def authorize(payload: TelegramAuth):
client = await get_telegram_client(payload.session)
await client.connect()
await client.send_code_request(payload.phone)
await client.sign_in(code=payload.code, phone=payload.phone)
return {'msg': 'signed in'}
I'm assuming you're using .start() for that.
.start() accepts a callback that is by default input() you can pass your own input like so.
client.start(code_callback=your_callback) and your callback should should return the code.
This can all be found here in the start docs

Best way to use httpx async client and tenacity?

I'm getting fairly different results with two different implementations.
Here is implementation 1
request_semaphore = asyncio.Semaphore(5)
async def _send_async_request(client: AsyncClient, method, auth, url, body):
async with request_semaphore:
try:
async for attempt in AsyncRetrying(stop=stop_after_attempt(3), wait=wait_fixed(1)):
with attempt:
response = await client.request(method=method, url=url, auth=auth, json=body)
response.raise_for_status()
return response
except RetryError as e:
pass
And here is implementation 2:
request_semaphore = asyncio.Semaphore(5)
#retry(stop=stop_after_attempt(3), wait=wait_fixed(1))
async def _send_single_async_request(self, client: AsyncClient, method, auth, url, body):
async with request_semaphore:
response = await client.request(method=method, url=url, auth=auth, json=body)
response.raise_for_status()
return response
async def _send_async_request(self, client: AsyncClient, method, auth, url, body):
try:
await self._send_single_async_request(client, method, auth, request)
except RetryError as e:
pass
I'm testing it against a stable REST API. Here are the bench marks:
100 successful POST requests:
Implementation 1: 0:59 mins
Implementation 2: 0:57 mins
100 failed POST requests:
Implementation 1: 3:26 mins
Implementation 2: 2:09 mins
These results are consistent. Can anyone help me understand why my first implementation is slower than my second?
edit: FYI, here's how i'm calling the above functions (the above funcs actually receive a request tuple with url and body, edited it for clarity)
async def _prepare_async_requests(method, auth, requests):
async with AsyncClient() as client:
task_list = [self._send_async_request(client, method, auth, request) for request in requests]
return [await task for task in asyncio.as_completed(task_list)]
def send_async_requests(auth, method, requests):
loop = asyncio.get_event_loop()
responses = loop.run_until_complete(self._prepare_async_requests(method, auth, requests))
return responses

Change the HTTP status code with a Google Cloud Function Promise

My code checks if a user is authorized, if the user is, the proper code is run. If the user is not, it run reject() to reject the promise.
If I run the code authenticated, I get
{"error":{"status":"INVALID_ARGUMENT","message":"Bad Request"}}
I am trying to change the status code to Forbidden (code 403) which you would normally do with res.status(403) however since this is a promise it is different. How can I change the error code returned?
My code is as follows:
const cloudFunction = functions.https.onCall((data, context) => {
return new Promise(function(resolve, reject) {
auth.verifyIdToken(data.userId).then(function(decodedToken) {
if(claims.admin === true) {
// Run code if user has admin role
}
else {
reject()
// Return error code 403 because user does not have admin role
}
}).catch(err => reject(err)) // Return error code 401 because user is not logged in
})
});
You can't change the HTTP status for a callable function. Callable functions essentially take over and hide the HTTP protocol for the request and response. All you do is specify the input and output objects, and the SDKs handle everything else.
If you need to control the HTTP status of a response, you will have to use a regular HTTP type function instead. Then you will have full control over the request and response.

Resources