How to access trailing metadata from python gRPC client - grpc

Here is how I am sending the metadata from server.
def DoSomething(self, request, context):
response = detection2g_pb2.SomeResponse()
response.message = 'done'
_SERVER_TRAILING_METADATA = (
('method_status', '1010'),
('error', 'No Error')
)
context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
return response
Here is what I tried:
res = _stub.DoSomething(req)
print (res.trailing_metadata())
In this case I get Attribute Error object has no attribute 'trailing_metadata'. I want to know way to access the trailing metadata in the client side.

I apologize that we don't yet have an example illustrating metadata but you can see here how getting the trailing metadata on the invocation side requires using with_call (or future, but that may change the control flow in a way that you don't want changed, so I think that with_call should be your first choice). I think your invocation-side code should look like
response, call = _stub.DoSomething.with_call(request)
print(call.trailing_metadata())
.

Related

What is the Correct Endpoint for the Form Recognizer API?

Docs about using the Azure's Form Recognizer seem unclear. What is the correct ENDPOINT to send my request?
I'm using python and have followed the docs to use the prebuilt receipt model of Form Recognizer but don't get the expected output. I'm unsure if I'm using the correct endpoint. I tried two things:
Reading this tutorial, it is stated that I need to look up the <ENDPOINT> in my resource's overview page. In my case it is: formextractor.cognitiveservices.azure.com. So I tried this:
import http.client, urllib.request, urllib.parse, urllib.error, base64
params = urllib.parse.urlencode({
})
# key = '...'
headers = {
# Request headers
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': key,
}
source = r"https://www.w3.org/WAI/WCAG20/Techniques/working-examples/PDF20/table.pdf"
body = {"url":source}
body = json.dumps(body)
try:
conn = http.client.HTTPSConnection('formextractor.cognitiveservices.azure.com')
conn.request("POST", "/formrecognizer/v1.0-preview/prebuilt/receipt/asyncBatchAnalyze?s" % params, f"{body}", headers)
response = conn.getresponse()
data = response.read()
operationURL = "" + response.getheader("Operation-Location")
print ("Operation-Location header: " + operationURL)
conn.close()
except Exception as e:
print(e)
This returns:
[Errno 8] nodename nor servname provided, or not known
But in the API Docs the ENDPOINT is already fixed to westeurope.api.cognitive.microsoft.com, which is where my resource is located. So I tried this:
# ... same headers, body and params as before
try:
conn = http.client.HTTPSConnection('westeurope.api.cognitive.microsoft.com')
conn.request("POST", "/formrecognizer/v1.0-preview/prebuilt/receipt/asyncBatchAnalyze?%s" % params, f"{body}", headers)
response = conn.getresponse()
data = response.read()
operationURL = "" + response.getheader("Operation-Location")
print ("Operation-Location header: " + operationURL)
conn.close()
except Exception as e:
print("[Errno {0}] {1}".format(e.errno, e.strerror))
Outputs an URL where I see:
{"error":{"code":"401","message": "Access denied due to invalid subscription key or wrong API endpoint. Make sure to provide a valid key for an active subscription and use a correct regional API endpoint for your resource."}}
I am certain I'm using the correct key. But in any case neither of the two seems to work. Could you help me? Thank you.
It looks like the initial documentation you are mentioning is misleading. You can find the endpoint of your resource in Azure portal, in the resource overview. Sample for mine:
Form Recognizer API is (at the time of writing this answer) hosted in the following Azure regions:
West US 2 - westus2.api.cognitive.microsoft.com
West Europe - westeurope.api.cognitive.microsoft.com
So in my case it's WestEurope, and as you mentioned it is the same on your resource. Once you got it, you then got a 401 Unauthorized
Several possibilities:
You made an error in the way you are passing the header (wrong key name, wrong key value), but it looks okay based on your code above (but I'm not used to Python)
Your resource is not from the same region as the endpoint you are querying (please double check)
You are using the right root, but something is wrong in how you are calling it
Once you have checked your region / key values, can you remove your ?%s"%params from your query? The Analyze Receipt method don't have params in query string (given documentation)

Posting binary buffer payload using Node-RED

I am trying to send a byte array through POST using Node-RED. I can successfully create the buffer using this module and storing it in msg.payload. However I can't figure out how to add it as a parameter in a http request node.
The receiving application requires enclosing quotes. So I use the payload in the following url: localhost:port/path?var=\"{{payload}}\", but it gives
"Error converting http params to args: invalid character '\' looking for beginning of value"
If using it in the request url without quotes: localhost:port/path?var={{payload}} nothing gets through (I can see on the other end).
I am using Protobuf due to the application on the other side, but I've also tried creating a buffer, as described here. However, nothing changes.
POSTs should not have arguments in the URL. The data should all be in the body.
Do you need to make the msg.payload an object with keys matching the arg names.
msg.payload = {
var = [buffer]
}
You will probably have to play around with the content-type header as by default I believe Node-RED will send a JSON body and you probably want application/x-www-form-urlencoded
You can set the headers by adding a msg.headers object

How to reuse variables from previous request in the Paw rest client?

I need to reuse value which is generated for my previous request.
For example, at first request, I make a POST to the URL /api/products/{UUID} and get HTTP response with code 201 (Created) with an empty body.
And at second request I want to get that product by request GET /api/products/{UUID}, where UUID should be from the first request.
So, the question is how to store that UUID between requests and reuse it?
You can use the Request Sent Dynamic values https://paw.cloud/extensions?extension_type=dynamic_value&q=request+send these will get the value used last time you sent a requst for a given request.
In your case you will want to combine the URLSentValue with the RegExMatch (https://paw.cloud/extensions/RegExMatch) to first get the url as it was last sent for a request and then extract the UUID from the url.
e.g
REQUEST A)
REQUEST B)
The problem is in your first requests answer. Just dont return "[...] an empty body."
If you are talking about a REST design, you will return the UUID in the first request and the client will use it in his second call: GET /api/products/{UUID}
The basic idea behind REST is, that the server doesn't store any informations about previous requests and is "stateless".
I would also adjust your first query. In general the server should generate the UUID and return it (maybe you have reasons to break that, then please excuse me). Your server has (at least sometimes) a better random generator and you can avoid conflicts. So you would usually design it like this:
CLIENT: POST /api/products/ -> Server returns: 201 {product_id: UUID(1234...)}
Client: GET /api/products/{UUID} -> Server returns: 200 {product_detail1: ..., product_detail2: ...}
If your client "loses" the informations and you want him to be later able to get his products, you would usually implement an API endpoint like this:
Client: GET /api/products/ -> Server returns: 200 [{id:UUID(1234...), title:...}, {id:UUID(5678...),, title:...}]
Given something like this, presuming the {UUID} is your replacement "variable":
It is probably so simple it escaped you. All you need to do is create a text file, say UUID.txt:
(with sample data say "12345678U910" as text in the file)
Then all you need to do is replace the {UUID} in the URL with a dynamic token for a file. Delete the {UUID} portion, then right click in the URL line where it was and select
Add Dynamic Value -> File -> File Content :
You will get a drag-n-drop reception widget:
Either press the "Choose File..." or drop the file into the receiver widget:
Don't worry that the dynamic variable token (blue thing in URL) doesn't change yet... Then click elsewhere to let the drop receiver go away and you will have exactly what you want, a variable you can use across URLs or anywhere else for that matter (header fields, form fields, body, etc):
Paw is a great tool that goes asymptotic to awesome when you explore the dynamic value capability. The most powerful yet I have found is the regular expression parsing that can parse raw reply HTML and capture anything you want for the next request... For example, if you UUID came from some user input and was ingested into the server, then returned in a html reply, you could capture that from the reply HTML and re-inject it to the URL, or any field or even add it to the cookies using the Dynamic Value capabilities of Paw.
#chickahoona's answer touches on the more normal way of doing it, with the first request posting to an endpoint without a UUID and the server returning it. With that in place then you can use the RegExpMatch extension to extract the value from the servers's response and use it in subsequent requests.
Alternately, if you must generate the UUID on the client side, then again the RegExpMatch extension can help, simply choose the create request's url for the source and provide a regexp that will strip the UUID off the end of it, such as /([^/]+)$.
A third option I'll throw out to you, put the UUID in an environment variable and just have all of your requests reference it from there.

Lua : Fetch a webpage

I want to fetch a webpage and get the result in a string, but I don't know how to do it. I search online and didn't find how to do it.
I'd simply use Lua Socket which comes with an http submodule. You can simply use http.request to get a webpage into whatever container you'd want (default is string, but you can use a table, a file, stdio, ... using ltn12 filters and sinks).
As an example:
local http=require'socket.http'
local body, statusCode, headers, statusText = http.request('http://w3.impa.br/~diego/software/luasocket/http.html')
print('statusCode ', statusCode)
print('statusText ', statusText)
print('headers ')
for index,value in pairs(headers) do
print("\t",index, value)
end
print('body',body)
If you can't find an exact http client library, you could implement on yourself, or build on someone else's work.
In that link, although it is called libhttpd, but the author clearly states that it can be used for anything. Looks like a more usable wrapper around lua sockets.
if you don't have socket (like me), but you have the http library/module, then you could try this:
http.get("https://nodemcu.readthedocs.io/en/master/en/modules/http/", nil, function(code, data)
if (code ~= 200) then
print("HTTP request failed")
else
print(code, data)
end
end)
it works for me
you can find more info in the docs https://nodemcu.readthedocs.io/en/master/en/modules/http/#httpget

Is it considered bad practice to perform HTTP POST without entity body?

I need to invoke a process which doesn't require any input from the user, just a trigger. I plan to use POST /uri without a body to trigger the process. I want to know if this is considered bad from both HTTP and REST perspectives?
I asked this question on the IETF HTTP working group a few months ago. The short answer is: NO, it's not a bad practice (but I suggest reading the thread for more details).
Using a POST instead of a GET is perfectly reasonable, since it also instructs the server (and gateways along the way) not to return a cached response.
POST is completely OK. In difference of GET with POST you are changing the state of the system (most likely your trigger is "doing" something and changing data).
I used POST already without payload and it "feels" OK. One thing you should do when using POST without payload: Pass header Content-Length: 0. I remember problems with some proxies when I api-client didn't pass it.
If you use POST /uri without a body it is something like using a function which does not take an argument .e.g int post (void); so it is reasonable to have function to your resource class which can change the state of an object without having an argument. If you consider to implement the Unix touch function for a URI, is not it be good choice?
Yes, it's OK to send a POST request without a body and instead use query string parameters. But be careful if your parameters contain characters that are not HTTP valid you will have to encode them.
For example if you need to POST 'hello world' to and end point you would have to make it look like this: http://api.com?param=hello%20world
Support for the answers that POST is OK in this case is that in Python's case, the OpenAPI framework "FastAPI" generates a Swagger GUI (see image) that doesn't contain a Body section when a method (see example below) doesn't have a parameter to accept a body.
the method "post_disable_db" just accepts a path parameter "db_name" and doesn't have a 2nd parameter which would imply a mandatory body.
#router.post('/{db_name}/disable',
status_code=HTTP_200_OK,
response_model=ResponseSuccess,
summary='',
description=''
)
async def post_disable_db(db_name: str):
try:
response: ResponseSuccess = Handlers.databases_handler.post_change_db_enabled_state(db_name, False)
except HTTPException as e:
raise (e)
except Exception as e:
logger.exception(f'Changing state of DB to enabled=False failed due to: {e.__repr__()}')
raise HTTPException(HTTP_500_INTERNAL_SERVER_ERROR, detail=e.__repr__())
return response

Resources