I have written an Alexa hosted skill, which I would like to open source as a friend would like to join me in working on it. It uses Googles Geocoding Api, which relies on an API key. Currently, this API key sits In my python source code:
...
import logging
GOOGLE_API_KEY = "KEY"
GOOGLE_GEOCODE_API_PATH = "https://maps.googleapis.com/maps/api/geocode/json?"
def get_lat_lon(address):
...
I want to upload my source code to GitHub (preferably public), whilst still hosting the application (ultimately a lambda function) using Alexa Hosting, which is eases up a lot of the infrastructure. Is there any way to define environment variables for an Alexa hosted application, so that my private API key is hidden?
This is a suggestion. Store your API key on dynamoDB and fetch whenever required. You will need to write an extra piece of code that reads from dynamoDB using boto3 library and then store the key on your variable.
import logging
GOOGLE_API_KEY = get_apikey_db()
GOOGLE_GEOCODE_API_PATH = "https://maps.googleapis.com/maps/api/geocode/json?"
def get_apikey_db():
#read from db here
def get_lat_lon(address):
...
I hope this solves your problem.
Related
My GAE app publishes some APIs in GCP and uses the following structure:
# Replace the following lines with client IDs obtained from the APIs
# Console or Cloud Console.
WEB_CLIENT_ID = '????????????.apps.googleusercontent.com'
ALLOWED_CLIENT_IDS = [WEB_CLIENT_ID, endpoints.API_EXPLORER_CLIENT_ID]
SCOPES = [endpoints.EMAIL_SCOPE]
#endpoints.api(name=API_NAME,
version=API_VERSION,
description='An API to manage languages',
allowed_client_ids=ALLOWED_CLIENT_IDS,
scopes=SCOPES)
My doubt is if someone picks this source code from my machine or GitHub project. He or she can access the APIs using the discovered web client id.
What’s the best practice in this case?
I acknowledge that the client can expose the ID and someone have access to it. But I believe that is another matter.
There are many ways you can do this. One way is to always check in a default value for the client ID, so that when people check out your code, they have to modify it to deploy it. You can also move the client ID to its own module and not check it in at all, and make the expectation that they create their own module with their own client ID. This avoids having a modified state for a checked in file all of the time.
The client ID itself is not sufficient information to generate a valid token. The cryptography involved will prevent such a person from accessing your API.
I've just started on Google Cloud and I'm creating an iOS app to interact with Google Cloud services via a mobile backend. I'm using Python to write the backend for App Engine. I've gone through the tutorials in creating an API based on endpoints - but I have a question.
Do I have to create a Cloud Endpoints API, and then an app on App Engine? Basically, I want to be able to register accounts on my iOS app, call an API which then makes use of Google Datastore to store the account details. From looking at the tutorials (both the cloud endpoints one and then the guestbook one), am I meant to expose Google Datastore, cloud storage etc. within the endpoints api? Or does that link into another app where that is all done?
Sorry if this sounds a bit silly, but I just want to make sure!
Thanks in advance.
In a nutshell, your Cloud Endpoints API is your application. Some of the documentation regarding Cloud Endpoints can be a bit confusing (or vague), but on the server side it's essentially a bunch of Python decorators or Java annotations that allow you to expose your application logic as a REST API.
I find the Java implementation of Cloud Endpoints more intuitive than the Python one, which requires a bit more work to (de-)serialise your objects. You could look at endpoints_proto_datastore.ndb.EndpointsModel which might take some of the boilerplate stuff out of the equation (defining messages).
Essentially, when you write your API, each endpoint maps to a python function. Inside that function you can do what you like, but typically it will be either:
Deserialise your POSTed JSON, validate it, and write some entities to Datastore (or Cloud SQL, BigTable, wherever).
Read one or more entities from Datastore and serialize them to JSON and return them to the client.
For example, you might define your API (the whole collection of endpoint functions) as
#endpoints.api(name='cafeApi', version='v1', description='Cafe API', audiences=[endpoints.API_EXPLORER_CLIENT_ID])
class CafeApi(remote.Service):
# endpoints here
For example, you might have an endpoint to get nearby cafes:
#endpoints.method(GEO_RESOURCE, CafeListResponse, path='cafes/nearby', http_method='GET', name='cafes.nearby')
def get_nearby_cafes(self, request):
"""Get cafes close to specified lat,long"""
cafes = list()
for c in search.get_nearby_cafes(request.lat, request.lon):
cafes.append(c.response_message())
return CafeListResponse(cafes=cafes)
A couple of things to highlight here. With the Python Endpoints implementation, you need to define your resource and message classes - these are used to encapsulate request data and response bodies.
So, in the above example, GEO_RESOURCE encapsulates the fields required to make a GeoPoint (so we can search by location using Search API, but you might just search Datastore for Cafes with a 5-star rating):
GEO_RESOURCE = endpoints.ResourceContainer(
message_types.VoidMessage,
lat=messages.FloatField(1, required=True),
lon=messages.FloatField(2, required=True)
)
and the CafeListResponse would just encapsulate a list of CafeResponse objects (with Cloud Endpoints you return a single object):
class CafeListResponse(messages.Message):
locations = messages.MessageField(CafeResponse, 1, required=False, repeated=True)
where the CafeResponse is the message that defines how you want your objects (typically Datastore entities) serialised by your API. e.g.,
class LocationResponse(messages.Message):
id = messages.StringField(1, required=False)
coordinates = messages.MessageField(GeoMessage, 3, required=True)
name = messages.StringField(4, required=False)
With that endpoint signature, you can access it via an HTTP GET at /cafeApi/v1/cafes/nearby?lat=...&lon=... or via, say, the Javascript API client with `cafeApi.cafes.nearby(...).
Personally, I found Flask a bit more flexible with working with Python to create a REST API.
I'm new to app engine, python an web development in general. I have an issue that i don't know how to solve. I want to maintain in the server an tuple with values that the user select. I pass this values to the server in the parameters of the page.
But the problem is that this tuple is modified by all the users and I want that each user can have his own values. The users aren't identified.
I've been looking for how to solve it, and I found some answers here in stackoverflow, but major part of them are more than 2 years old, and I think that I need to use the library gaeutilities, but not sure about it, and If Google have an “official” solution to maintain session variables with python in app engine.
I defined the var “categoria” as a class variable,
class returnElements(webapp2.RequestHandler):
categoria = []
def get(self):
…...
cat = str(self.request.get("cat"))
self.categoria.append(cat)
…...
app = webapp2.WSGIApplication([
('/returnElements', returnElements),
…....
and here the url
http://localhost:13080/returnElements?cat=Sudaderas
It works fine, but just with one user at time :-(
By the way Im new to stackoverflow, sorry in advance if the question isn't accurate or solved in another thread.
In any web app, you must never store user-specific data in module or class-level variables as they will be shared by all users.
If you need to persist data for a user, save it in the datastore! That's what it's for. There are various implementations of user-specific sessions, such as the gaeutilities library which you link to. That library has full documentation which you should read.
My method names get translated from some_method to apiname.resource.somemethod and gapi.client.apiname.resource.somemethod. Example:
#endpoints.method(messages.VoidMessage, messages.VoidMessage,
name='resource.some_method', path='resource/some_method' )
def resource_some_method(self, request):
pass
I've also tested by naming a method with a few underscores in between.
Can this be stopped?
No. Google's API Infrastructure has strict naming guidelines and these are "enforced" by the SDK code. When deploying your application, your API definition is translated into an API configuration file which is sent of to Google's API Infrastructure to spin up a Discovery-based API of your very own.
Before creating this API config, these names are parsed by the endpoints.message_parser library (called from endpoints.api_config) to make sure your names adhere to the specification. In particular:
split_name = re.split(r'[^0-9a-zA-Z]', name)
normalized = ''.join(
part[0].upper() + part[1:] for part in split_name if part)
You are free to circumvent this code and generate your own API configuration, but the API deployment will fail as those names will be rejected by Google's API Infrastructure when you deploy.
I'm programming an application with google app engine, with django 1.1 (no django pacth or others), well as you know is impossible use django login and session features so I download
Gae utility and use Session Object (http://gaeutilities.appspot.com/) but some time this object create 2 sessions instead 1 session ... here's code
def index(request):
aSWrap = SWrap(SWrap.createSession())
....
def login(request):
aSWrap = SWrap(SWrap.createSession())
....
class SWrap(object):
#classmethod
def createSession():
return Session(cookie_name='my_cookie',session_expire_time=7200)
and for setting session no expiration or really long expiration...enter code here
Thanks
Judging by the code, you're calling createsession twice within the same request. That will cause problems with David's library as well.
Also, gaeutilties session included a config file where you can modify all the default values as you like.
https://github.com/joerussbowman/gaeutilities/blob/master/appengine_utilities/settings_default.py
gaeutilities session also has security features lacking in gae-sessions. I'm afraid David didn't attempt to answer you question, rather just suggested you use his library which under your current implementation would have the exact same problem. You need to be sure you only initiate the session once per http request no matter what session library you're using.
I'm moving gaeutilities session to a decorator in order to address this issue as well and provide better performance. You can watch the master branch on Github for updates. https://github.com/joerussbowman/gaeutilities
I suggest using a different sessions library. Check out this comparison of the available sessions libraries for GAE.
I'd recommend gae-sessions - it presents an API almost identical to the library you are currently using, but it is much faster and shouldn't give you headaches like the bug you've encountered above.
Disclaimer: I wrote gae-sessions, but I'm not the only one who would recommend it. Here is a recent thread discussing sessions on the google group for GAE python.
What are you trying to do with SWrap(SWrap.createSession())? It looks like the result of SWrap.createSession() is passed to the SWrap() constructor. Have you omitted part of the definition of SWrap?
Perhaps this is more what you are wanting:
def index(request):
mysession = SWrap.createSession()
....
def login(request):
mysession = SWrap.createSession()
....
class SWrap(object):
#staticmethod
def createSession():
return Session(cookie_name='my_cookie',session_expire_time=7200)