I am new to FastAPI framework, I want to print out the response status code from a PUT request.
#app.put('/user/{id}', status_code=status.HTTP_200_OK)
async def processing(id: str, request: Request, response: Response):
data = await request.json()
status = response.status_code
print(status_code)
logger.info("Got response [%s]", status)
return data
The status returned is 'None'. But uvicorn server shows a 200 OK status. How can I include this code in my logging/print out?
Thanks.
Related
I started looking into websockets and I would liek to implement realtime communication between web-client (Angular 13) and Python app. As backend I used Django with implemented websockets and channels
As i am having problem i simplified code as much as i could so a lot of values are hardcoded for a sake to make it work. (Right now it is One WebClient and one Bot)
I implemented 2 Consumers. Bot and webclient:
class BotConsumer(AsyncJsonWebsocketConsumer):
async def connect(self):
await self.accept()
await self.channel_layer.group_add("bot","dev")
async def disconnect(self, close_code):
await self.channel_layer.group_discard("bot","dev")
async def receive(self, text_data):
await self.channel_layer.group_send("dev",{"type": "recv","text": "test"})
print("Data sent to group")
class WebClientConsumer(AsyncJsonWebsocketConsumer):
async def connect(self):
await self.accept()
await self.channel_layer.group_add("client","dev")
async def recv(self,event):
print("Consumer received smthing from channels")
async def disconnect(self, close_code):
await self.channel_layer.group_discard("client","dev")
async def receive(self, text_data):
print("Smthing received")
my channel_layer setup in Setting.py
CHANNEL_LAYERS = {
'default': {
# 'BACKEND': 'channels_redis.core.RedisChannelLayer',
# 'CONFIG': {
# "hosts": [('192.168.1.10', 6379)],
# },
"BACKEND": "channels.layers.InMemoryChannelLayer"
}}
I tried both Redis with local server running and in memory channels
My websocket's routing.py:
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r'live/bot', consumers.BotConsumer.as_asgi()),
re_path(r'live/webclient', consumers.WebClientConsumer.as_asgi()),
]
My behavior:
Django logs:
HTTP POST /core/UpdateAvailableServers 200 [0.07, 127.0.0.1:50494]
HTTP POST /core/GetPostInfo 200 [0.02, 127.0.0.1:50497]
**WebSocket HANDSHAKING /live/bot [127.0.0.1:50498]**
**WebSocket CONNECT /live/bot [127.0.0.1:50498]**
HTTP POST /core/GetStatus 200 [0.00, 127.0.0.1:50501]
HTTP POST /core/GetPostInfo 200 [0.02, 127.0.0.1:50504]
HTTP POST /core/GetBots 200 [0.00, 127.0.0.1:50524]
**WebSocket HANDSHAKING /live/webclient [127.0.0.1:50527]**
**WebSocket CONNECT /live/webclient [127.0.0.1:50527]**
HTTP POST /core/GetStatus 200 [0.01, 127.0.0.1:50528]
HTTP POST /core/UpdateAvailableServers 200 [0.02, 127.0.0.1:50531]
HTTP POST /core/GetPostInfo 200 [0.02, 127.0.0.1:50534]
HTTP POST /core/GetStatus 200 [0.00, 127.0.0.1:50537]
HTTP POST /core/GetPostInfo 200 [0.02, 127.0.0.1:50540]
HTTP POST /core/UpdateAvailableServers 200 [0.06, 127.0.0.1:50544]
HTTP POST /core/GetStatus 200 [0.00, 127.0.0.1:50547]
HTTP POST /core/GetPostInfo 200 [0.02, 127.0.0.1:50550]
**Data sent to group**
HTTP POST /core/GetPostInfo 200 [0.00, 127.0.0.1:50554]
HTTP POST /core/GetStatus 200 [0.00, 127.0.0.1:50557]
HTTP POST /core/UpdateAvailableServers 200 [0.06, 127.0.0.1:50560]
HTTP POST /core/GetPostInfo 200 [0.02, 127.0.0.1:50563]
As you can see in the log i got successfull websocket connection from my python app (BOT) and also angular app (WebClient) Both are added into group at connect Function.
Bot app will then send some data using websockets and they are suppose to be send to whole group which I will get confirmation as it is shown in log.
Problem is that My webclient will totally ignore this. recv method is never executed nor WebClient consumer will not show any activity on this action.
Is there some obvious mistake I am doing? (I can provide any additional info if needed)
You are not supposed to create a custom channel. Assign a custom group to the channel instead.
await self.channel_layer.group_add("bot",self.channel_name)
Also, send the socket message to the client group in the same channel.
await self.channel_layer.group_send("client",{
"type":"recv",
"message":text_data
})
See the corrected implementation below.
class BotConsumer(AsyncJsonWebsocketConsumer):
async def connect(self):
await self.accept()
await self.channel_layer.group_add("bot",self.channel_name)
async def disconnect(self, close_code):
await self.channel_layer.group_discard("bot",self.channel_name)
async def receive(self, text_data):
await self.channel_layer.group_send("client",{
"type":"recv",
"message":text_data
})
print("Data sent to group")
class WebClientConsumer(AsyncJsonWebsocketConsumer):
async def connect(self):
await self.accept()
await self.channel_layer.group_add("client",self.channel_name)
async def recv(self,event):
print("Consumer received smthing from channels")
async def disconnect(self, close_code):
await self.channel_layer.group_discard("client",self.channel_name)
async def receive(self, text_data):
print("Smthing received")
I am building API using Flask Restx. I had written a generic exception handler which will throw an error message and code in Json format.
#app.errorhandler(APIError)
def handle_invalid_usage(error):
logger.opt(exception=True).error(error)
response = jsonify(error.to_dict())
response.status_code = error.status_code
return response
I am trying to write unit test using pytest for testing error condition(Resource Not Found). My unit test does return only 500 Internal server error (response.status_code) instead of the going through the error handler and returning 404. When I test it directly using Postman it works perfect.
#pytest.fixture(scope="session")
def app():
app = create_app()
return app
#pytest.fixture
def client(app):
return app.test_client()
def test_get_sequence_resource_not_found(mocker: MockerFixture, client: FlaskClient):
mocked = mocker.patch("service.ViewSequenceService.get_sequence")
mocked.side_effect = ResourceNotFound('Sequence id Not Present')
response = client.get("/sequence/f15a9f6e-7a1d-4d12-99c3-fb80d4bc98a1")
json_data = json.loads(response.data)
assert response.status_code == 404
assert json_data['payload']['message'] == 'Sequence id Not Present'
assert json_data['payload']['status'] == 404
Was running into the same issue. It seems that for pytest to recognize it the exception has to registered with the API instead of the app.
from flask_restx import Api
class APIError(Exception):
status_code = 400
content = {"error": "Bad request"}
api = Api()
#api.errorhandler(APIError)
def handle_invalid_usage(exc: APIException):
return exc.content, exc.status_code
I was trying AioHttp TestCase library and just using the sample code given in the docs but it says 404 when I run pytest filename.py.
I see some examples above too, first of all I don't understand the difference between test_client and self.client. Are they both doing the same thing but just different methods?
Also, in the below implementation, where do you pass the handler info? self.client does not accept handler param hello.
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from aiohttp import web
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from aiohttp import web
async def hello(request):
return web.Response(text='Hello')
class MyAppTestCase(AioHTTPTestCase):
async def get_application(self):
return web.Application()
#unittest_run_loop
async def test_example(self):
request = await self.client.request("GET", "/")
assert request.status == 200
text = await request.text()
assert "Hello, world" in text
test_client fixture from pytest should be just factory that make is the same as AioHTTPTestCase.client
When I look to code in TestClient it all got down to cal _request that looks like this:
async def _request(
self,
method: str,
str_or_url: StrOrURL, *,
params: Optional[Mapping[str, str]]=None,
data: Any=None,
json: Any=None,
cookies: Optional[LooseCookies]=None,
headers: LooseHeaders=None,
skip_auto_headers: Optional[Iterable[str]]=None,
auth: Optional[BasicAuth]=None,
allow_redirects: bool=True,
max_redirects: int=10,
compress: Optional[str]=None,
chunked: Optional[bool]=None,
expect100: bool=False,
raise_for_status: Optional[bool]=None,
read_until_eof: bool=True,
proxy: Optional[StrOrURL]=None,
proxy_auth: Optional[BasicAuth]=None,
timeout: Union[ClientTimeout, object]=sentinel,
verify_ssl: Optional[bool]=None,
fingerprint: Optional[bytes]=None,
ssl_context: Optional[SSLContext]=None,
ssl: Optional[Union[SSLContext, bool, Fingerprint]]=None,
proxy_headers: Optional[LooseHeaders]=None,
trace_request_ctx: Optional[SimpleNamespace]=None
) -> ClientResponse:
So you can pass these to client and it will make the call. data and json should be the same (expecting as in requests it is like so), json just dumps it.
So something like this should work. At least for me:
class BookingTest(AioHTTPTestCase):
async def get_application(self):
return await create_test_app()
#unittest_run_loop
async def test_create_booking(self):
data = {
"my_id": "1234"
}
# the post data should be in request.body
# (we use connexion and we have it parsed as an argument to handler named body)
resp = await self.client.request("POST", "/api/bookings", json=data)
assert resp.status == 201
#unittest_run_loop
async def test_get_booking(self):
booking_id = "1234"
url = f"/be/api/bookings/{booking_id}"
resp = await self.client.request("GET", url)
assert resp.status == 200
I have the following code.
params = {'client_id':settings.SOCIAL_AUTH_INSTAGRAM_KEY,
'client_secret':settings.SOCIAL_AUTH_INSTAGRAM_SECRET,
'aspect':'media',
'object':'tag',
'object_id':instance.hashtag,
'callback_url':
'http://subdomain.domain.net:8000/campaigns/hook'}
response = requests.post('https://api.instagram.com/v1/subscriptions',
data=params)
And I get response
'{"meta":{"error_type":"APISubscriptionError","code":400,"error_message":"Invalid
response"}}'
My domain is reachable from outside. Any ideas?
This was because Instagram sends a GET request to my callback_url
and wants me to response with hub.challenge parameter like below
if self.request.GET:
response = request.GET.get('hub.challenge')
return HttpResponse(response)
I have already test this before and it's work. Now the error back again and I didn't do any changes on my social app.
Here are my codes:
def get_profile(request, token=None):
args = {
'client_id': settings.FACEBOOK_APP_ID,
'client_secret': settings.FACEBOOK_APP_SECRET,
'redirect_uri': request.build_absolute_uri(reverse('social:fb_callback')),
'code': token,
}
target = urllib.urlopen('https://graph.facebook.com/oauth/access_token?' + urllib.urlencode(args)).read()
response = cgi.parse_qs(target)
access_token = response['access_token'][-1]
return access_token
Obviously, your request is not successful and the response doesn't have an access token. According to facebook docs, when a request isn't good, it returns a response with an error element, something like:
{
error: {
message: "Missing redirect_uri parameter.",
type: "OAuthException",
code: 191
}
}
So, in your function, you should do something like:
class FacebookAccessException(Exception): pass
def get_profile(request, token=None):
...
response = json.loads(urllib_response)
if 'error' in response:
raise FacebookAccessException(response['error']['message'])
access_token = response['access_token'][-1]
return access_token
PS:
Try to use better urllib. You should try Requests.