Header and Body Data

While a querystring key is a good starting point for authentication, there are more secure and efficient methods available. is one such method. Oauth is an open standard for delegating access to internet users, first introduced in 2006. It currently exists in two distinct versions: 1.0 and 2.0. It is important to note that Oauth 2.0 is not backward compatible with 1.0, as they are entirely separate technical specifications.

Both versions of Oauth rely on an alternative method for passing data to web services, besides using querystring parameters. This method uses . Request headers are not visible in the URL querystring but are transmitted along with the URL when the web service is called, providing additional context and security.

Oauth 1.0 authentication requires four parameters: Consumer Key, Consumer Secret, Access Token, and Token Secret. These are essentially four keys that function similarly to the querystring keys used in earlier examples, such as the data.gov API. However, due to technical challenges, particularly around URL redirects, Oauth 2.0 was developed as an improved alternative. Oauth 2.0 uses a , which is a single, sizable token (approximately three times larger than a querystring key) sent as a header. This approach enhances security and simplifies the authentication process.

Oauth 2.0 is widely adopted and powers numerous modern web services, including those from cloud-based machine learning platforms like Azure ML Studio and AWS Machine Learning. For example, a demo web service you may have created in a previous class, based on the BikeBuyers.csv dataset, could illustrate how this works. This dataset contains information about consumers visiting a bicycle store, and the web service performs more than just returning data—it accepts data inputs and provides a prediction on whether a new customer will purchase a bike.

To make such a web service functional, additional values must be sent alongside the bearer token as inputs to the model, which are then used to generate a prediction. When working with large datasets or data structures more complex than a simple key/value dictionary, these inputs are typically sent in the . In the following example, you will see how all three inputs—parameters, headers, and body—are combined to interact with the web service.

      import requests
      import json
        
      # Define the input data structure
      data = {
        "Inputs": {
          "input1": [  # This is a list of feature sets; you can send multiple customers at a time
            { # Example of a customer's data
              "age": 19,              # Age of the customer
              "sex": "female",        # Gender of the customer
              "bmi": 27.9,            # BMI (Body Mass Index) of the customer
              "children": 0,          # Number of children the customer has
              "smoker": "yes",        # Smoking status: "yes" or "no"
              "region": "southwest"   # Geographic region: northeast, northwest, southeast, southwest
            },
            {  # Collect user inputs for another customer
              "age": int(input("What is your age? (enter a valid integer): ")),
              "sex": input("What is your gender? (female/male): "),
              "bmi": float(input("What is your BMI? (e.g., 21.3): ")),
              "children": int(input("How many children do you have? (enter an integer): ")),
              "smoker": input("Do you smoke? (enter yes or no): "),
              "region": input("Where do you live? (options: northeast, northwest, southeast, southwest): ")
            } # You could potentially add as many customers as you want to with additional dictionaries here
          ]
        }
      }
        
      # Encode the data as a JSON string
      body = str.encode(json.dumps(data))
        
      # Define the web service endpoint and API key
      url = 'http://772ac08d-cced-464d-b0e9-03f59d2f1fef.westcentralus.azurecontainer.io/score'
      api_key = 'qmvgoa0Yw2paT2ACX2n1D306aoEs1c8S'  # Replace with your actual API key
        
      # Set the headers for the HTTP request
      headers = {
        'Content-Type': 'application/json',  # Specify the format of the request body
        'Authorization': 'Bearer ' + api_key  # Include the API key for authorization
      }
        
      # Send the POST request to the endpoint; the result is immediately parsed as JSON for further use
      req = requests.post(url=url, data=body, headers=headers).json()
        
      # Print the raw response for debugging purposes
      print('\nRaw response from the API:', req, '\n')
        
      # Iterate through the response results to extract and display projected costs
      print("Customer projected costs:")
      for result in req['Results']['WebServiceOutput0']:
        # Format and right-align the printed cost value
        print(f"  Customer projected cost: ${result['Scored Labels']:>10.2f}")
        
      # Output:
      #  What is your age? (enter a valid integer): 45
      #  What is your gender? (female/male): male
      #  What is your BMI? (e.g., 21.3): 24.3
      #  How many children do you have? (enter an integer): 3
      #  Do you smoke? (enter yes or no): no
      #  Where do you live? (options: northeast, northwest, southeast, southwest): southeast
      #  
      #  Raw response from the API: {'Results': {'WebServiceOutput0': [{'Scored Labels': 25180.178081707592}, {'Scored Labels': 7992.073217857426}]}} 
      #  
      #  Customer projected costs:
      #    Customer projected cost: $  25180.18
      #    Customer projected cost: $   7992.07
      

Before we end, notice a couple of things. First, the request was a POST rather than a GET. Although parameters, body, and headers can be used with both GET and POST requests, the web service handles them a bit differently. However, we do not need to know how the web service processes this data in order to use it. We only need to know to format the request. Second, notice that the body needed to be JSON encoded before sending it. Each web service can require whatever format it wants for the body. The web service documentation will let you know how it wants the body encoded.