Google Cloud Endpoints adding extra parameters - google-cloud-endpoints

I'm using the 'endpoints-proto-datastore' library and a bit lost in how to add extra parameters to my requests.
Basically I want to add these fields [ID, token] with ID being required. Blossom.io is doing something similar, here Blossom.io Api
Here's my Post method
#Doctor.method(path='doctor', http_method='POST', name='doctor.insert')
def DoctorInsert(self, doctor):
#Edit
Without the Proto-Datastore library:
request = endpoints.ResourceContainer(
message_types.VoidMessage,
id=messages.IntegerField(1,variant=messages.Variant.INT32),
token=messages.IntegerField(2, variant=messages.Variant.INT32)
)
#endpoints.method(request, response,
path='doctor/{id}', http_method='POST',
name='doctor.insert')
How can I do the same using the proto-datastore library?

The way I do it is to add another property to the model decorated with #EndpointsAliasProperty and a setter. I wouldn't call it ID because it may confuse with the App Engine built-in ID.
class Doctor(EndpointsModel):
...
#EndpointsAliasProperty(
setter=set_doctorid, property_type=messages.StringField
)
def doctorid(self):
#Logic to retrieve the ID
return doctorid
def set_doctorid(self, value):
#The ID will be in the value, assign and store it in your model

Related

Fast API - post any key value data

I'm using Fast.API
I need an API to allow users to post any data, key/value - I use this to allow users to add custom profile key/value fields to profile, where key is of type string and value is string, number, boolean.
how do I add such route?
I'm using this route, but is not working:
#route.post('/update_profile')
def update_profile(acsess_token, **kargs):
# I need here to get a dictionary like this: { "name": "John", "nick_name": "Juju", "birth_year": 1999, "allow_newsletter": False, }
# and so on.... any key/value pair
pass
I want to be able to post to this route any pair(s) key/value. Is any way to do it with FastAPI?
Thank you.
you can use the request object directly
from fastapi import FastAPI
from fastapi import Request
#app.post("/something")
async def get_body(request: Request):
return await request.json()
After searching for a way to do it, I found this solution:
#route.post('/update_profile')
def update_profile(acsess_token, custom_fields: Optional[dict[str, Any]]):
pass
And this is the best solution so far (for me).

'deserializing' JSON to sqlalchemy model

I'm storing some RESTful api calls into a relational database using sqlalchemy, and I'm looking for a way to 'deserialize' or pythonify some or all of the incoming fields, for instance I might have a json object like
{
'id': 1,
'created_at': '2021-05-27T03:22:38Z',
'count': '3'
}
and I would like a way to "automatically" deserialize the data, similar to how djangorestframework serializers work where fields like "created_at" could be defined as datetime fields, and you could optionally cast 'count' as an integer, and run something like
...setup
# get the json from before as a dict
item = client.get_item()
# somehow serialize here
session = Session()
item_model = Item(**item_data[0])
session.add(item_model)
session.commit()
https://www.django-rest-framework.org/api-guide/serializers/
You have multiple well knowns module to perform serialization (independant of any framework):
Marshmallow: https://marshmallow.readthedocs.io/en/stable/
Typesystem (by the creator of DRF): https://github.com/encode/typesystem
You can also do your own serializer, based on DRF serializer code, if your use case is simple, or just perform a lookup of your dict fields that perform validation/transformation.

Web2py: Sending JSON Data via a Rest API post call in Web2py scheduler

I have a form whose one field is type IS_JSON
db.define_table('vmPowerOpsTable',
Field('launchId',label=T('Launch ID'),default =datetime.datetime.now().strftime("%d%m%y%H%M%S")),
Field('launchDate',label=T('Launched On'),default=datetime.datetime.now()),
Field('launchBy',label=T('Launched By'),default = auth.user.email if auth.user else "Anonymous"),
Field('inputJson','text',label=T('Input JSON*'),
requires = [IS_NOT_EMPTY(error_message='Input JSON is required'),IS_JSON(error_message='Invalid JSON')]),
migrate=True)
When the user submits this Form, this data is also simultaneously inserted to another table.
db.opStatus.insert(launchId=vmops_launchid,launchDate=vmops_launchdate
,launchBy=vmops_launchBy,opsType=operation_type,
opsData=vmops_inputJson,
statusDetail="Pending")
db.commit()
Now from the scheduler, I am trying to retrieve this data and make a POST request.
vm_power_opStatus_row_data = vm_power_opStatus_row.opsData
Note in the above step I am able to retrieve the data. (I inserted it in a DB and saw the field exactly matches what the user has entered.
Then from the scheduler, I do a POST.
power_response = requests.post(vm_power_op_url, json=vm_power_opStatus_row_data)
The POST request is handled by a function in my controller.
Controller Function:
#request.restful()
def vmPowerOperation():
response.view = 'generic.json'
si = None
def POST(*args, **vars):
jsonBody = request.vars
print "Debug 1"+ str(jsonBody) ##-> Here it returns blank in jsonBody.
But if I do the same request from Outside(POSTMAN client or even python request ) I get the desired result.
Is anything going wrong with the data type when I am trying to fetch it from the table.
power_response = requests.post(vm_power_op_url,
json=vm_power_opStatus_row_data)
It appears that vm_power_opStatus_row_data is already a JSON-encoded string. However, the json argument to requests.post() should be a Python object, not a string (requests will automatically encode the Python object to JSON and set the content type appropriately). So, the above should be:
power_response = requests.post(vm_power_op_url,
json=json.loads(vm_power_opStatus_row_data))
Alternatively, you can use the data argument and set the content type to JSON:
power_response = requests.post(vm_power_op_url,
data=vm_power_opStatus_row_data,
headers={'Content-Type': 'application/json')
Also, note that in your REST POST function, request.vars is already passed to the function as **vars, so within the function, you can simply refer to vars rather than request.vars.

Technique to get an id back with an http query when empty array is returned

Let me first say I have a solution to this problem, but I'm interested in knowing whether there is a better way, and whether I'm doing something wrong.
I have a table of objects on the front-end of a webapp, I need to asynchronously load some data for the objects as it is needed on a per-object basis. The server returns a JSON array containing the data for that object, and the data contains the object's key, so I can update the object on the front-end with its data. When there is no data, I just get an empty array, which unfortunately presents no way of updating the object, since I don't have the key to update it with. This can result in another query later, which is a waste of time/resources. I can't modify the server, is there a way to do this nicely?
My current solution is to just set the object's data to an empty array before sending the request, then just update when the result is received if the result is nonempty.
I was wondering if there is a better/more idiomatic way to do this.
For reference, I'm using Elm with PostgREST as the backend.
You can use currying and partial function application to indicate which object ID should be updated.
I'm assuming you have some code similar to this:
type Msg
= ...
| FetchData Int
| DataFetched [Data]
| DataFetchFail Http.Error
-- inside the update function
update msg model =
case msg of
...
FetchData id =
model ! [ Task.perform DataFetchFail DataFetched (Http.post ...) ]
If you define your DataFetched constructor to include the ID as the first parameter, you can use partial application to include the ID for future lookup, regardless of what the server returns.
Here's the same code chunks with this idea:
type Msg
= ...
| FetchData Int
| DataFetched Int [Data]
| DataFetchFail Http.Error
-- inside the update function
update msg model =
case msg of
...
FetchData id =
model ! [ Task.perform DataFetchFail (DataFetched id) (Http.post ...) ]
You could also add the ID to the Fail message for more fine-grained error messages.

How to get the table name in AWS dynamodb trigger function?

I am new with AWS and working on creating a lambda function on Python. The function will get the dynamodb table stream and write to a file in s3. Here the name of the file should be the name of the table.
Can someone please tell me how to get the table name if the trigger that is invoking the lambda function?
Thanks for help.
Since you mentioned you are new to AWS, I am going to answer descriptively.
I am assuming that you have set 'Stream enabled' setting for your DynamoDB table to 'Yes', and have set up this as an event source to your lambda function.
This is how I got the table name from the stream that invoked my lambda function -
def lambda_handler(event, context):
print(json.dumps(event, indent=2)) # Shows what's in the event object
for record in event['Records']:
ddbARN = record['eventSourceARN']
ddbTable = ddbARN.split(':')[5].split('/')[1]
print("DynamoDB table name: " + ddbTable)
return 'Successfully processed records.'
Basically, the event object that contains all the information about a particular DynamoDB stream that was responsible for that particular lambda function invoke, contains a parameter eventSourceARN. This eventSourceARN is the ARN (Amazon Resource Number) that uniquely identifies your DynamoDB table from which the event occurred.
This is a sample value for eventSourceARN -
arn:aws:dynamodb:us-east-1:111111111111:table/test/stream/2020-10-10T08:18:22.385
Notice the bold text above - test; this is the table name you are looking for.
In the line ddbTable = ddbARN.split(':')[5].split('/')[1] above, I have tried to split the entire ARN by ':' first, and then by '/' in order to get the value test. Once you have this value, you can call S3 APIs to write to a file in S3 with the same name.
Hope this helps.
Please note that eventSourceArn is not always provided. From my testing today, I didn't see eventSourceArn presented in record. You can also refer to the links:
Issue: https://github.com/aws/aws-sdk-js/issues/2226
API: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_Record.html
One way to do it will be via pattern matching in Scala using regex:
val ddbArnRegex: Regex = """arn:aws:dynamodb:(.+):(.+):table/(.+)/stream/(.+)""".r
def parseTableName(ddbARN: String): Option[String] = {
if (null == ddbARN) None
ddbARN match {
case ddbArnRegex(_, _, table, _) => Some(table)
case _ => None
}
}

Resources