How to retrieve Google Analytics data using OAuth in Function App written in Python

QiLi-8593 0 Reputation points
2023-03-07T01:20:41.63+00:00

My Python script works well locally to retrieve data from Google Analytics using OAuth client ID. After I deployed the code to Azure Function App, it doesn't work anymore.

Here is part of my code that involves Google Analytics OAuth:


 def get_ga_service(api_name, api_version, scope, client_secrets_path):
            """Get a service that communicates to a Google API.

            Args:
            api_name: string The name of the api to connect to.
            api_version: string The api version to connect to.
            scope: A list of strings representing the auth scopes to authorize for the
                connection.
            client_secrets_path: string A path to a valid client secrets file.

            Returns:
            A service that is connected to the specified API.
            
            """
            # Parse command-line arguments.
            parser = argparse.ArgumentParser(
                formatter_class=argparse.RawDescriptionHelpFormatter,
                parents=[tools.argparser])
            flags = parser.parse_args([])

            # Set up a Flow object to be used if we need to authenticate.
            flow = client.flow_from_clientsecrets(
                client_secrets_path, scope=scope,
                message=tools.message_if_missing(client_secrets_path))

        # Prepare credentials, and authorize HTTP object with them.
        # If the credentials don't exist or are invalid run through the native client
        # flow. The Storage object will ensure that if successful the good
        # credentials will get written back to a file.

            storage = file.Storage(api_name + '.dat')
            credentials = storage.get()
            if credentials is None or credentials.invalid:
                credentials = tools.run_flow(flow, storage, flags)
            http = credentials.authorize(http=httplib2.Http())

            # Build the service object.
            service = build(api_name, api_version, http=http)

            return service

# Define the auth scopes to request.
scope = ['https://www.googleapis.com/auth/analytics.readonly']

# Connect to Google Analytics account and get HttpRequest objec
service = get_ga_service('analytics', 'v3', scope, 'client_secrets.json')

# Parameters needed to retrieve needed data from Google Analytics
################ (Rest of the code) #########################
Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
5,908 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. MikeUrnun 9,777 Reputation points Moderator
    2023-03-08T06:20:41.4466667+00:00

    Hello @QiLi-8593 Thanks for reaching out and posting on the MS Q&A! You might have to refactor the code above and consider running it on Azure Durable Functions instead. Here's my feedback:

    • get_ga_service() function includes code for parsing command line arguments. Since you'll be running this function on Azure and the goal of the function is to return GA service object, do you really need the part that parses command line arguments?
    • The client secret is stored inside a client_secrets.json file that resides on the same filesystem alongside your Python function files and is referenced as a relative path. This has at least a couple of caveats: (a) referencing a file relatively can be error-prone and requires your Python app file to have read permission to the file. (b) Storing a secret in a flat file is risky and goes against best practices for security. Azure Functions offers integration with KeyVault for handling secrets but there are other options such as storing the secret via App Setting etc.
    • Same file handling concerns (of pathing & permissions) for writing to the analytics.dat file via Storage object.
    • The overall operation of the get_ga_service() function entails reading and writing to files on the same filesystem (i/o operation) as well as authenticating to GA service via HTTP (networking operation). These types of tasks are regarded as stateful workflow because such operations can fail. The operating system could crash and fail the reading/writing of files. HTTP calls to GA could fail due to networking issues. Because of those reasons, Azure Durable Functions is recommended service that is designed to handle such workflow and is highly recommended for your use case. The Azure Functions is designed for stateless tasks.

    I've made the suggestions above only based on the code that you provided. Since I'm unaware of the rest of the code, the structure of your functions, the exact error you may be hitting, how you're handling the deployment, and the configuration of your overall Function App, I'm sorry in advance if I misunderstood anything.

    However, if any of the feedback shared seems helpful and you'd like to learn more, let me know in the comments and I'd be happy to provide more info and resources.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.