Webex APIs with Python

While sending individual requests to Webex APIs is straightforward, automating tasks programmatically requires careful consideration. Most automation requires multiple API requests in series (or maybe even in parallel and aggregating multiple parallel responses), often using information from one response to construct a new request on a different API endpoint. You must consider the logic necessary to handle a variety of responses including errors and also grant your application access to the APIs while maintaining security. Python offers convenient libraries, such as requests and urllib that allow you to construct and send HTTP(S) requests, but merely constructing requests is insufficient for robust automation. This is not to say that you cannot work with Webex APIs by using a simple HTTP library like these, but you are then forced to deal with challenges such as handling pagination for large datasets and managing response codes indicating congestion, which may warrant retries rather than immediate failure.

To address these complexities, this lab will show you how to use a Software Development Kit (SDK) named wxc_sdk, accessible at https://pypi.org/project/wxc-sdk/. Initially designed for Webex Calling-specific APIs, this SDK has evolved to encompass the majority of Webex APIs, organized as individual 'packages' within the SDK.

To demonstrate the use of the SDK, start by performing the same user lookup you did earlier using the developer.webex.com documentation, but this time using Python. As with all Webex API interactions in this lab, you will use the wxc_sdk to simplify the task. Follow these steps to get started:

  1. Access your VS Code instance: https://dev1.pod6.col.lab:8443
  2. Click the Explorer icon at left, and you see a list of folders and files.
  3. Navigate to expand the examples folder and click to open wxc_enable_user.py. You now have the file open for editing.

  4. The file contains a basic Python skeleton that you will use to execute basic Webex API requests using the wxc_sdk. The Python environment has been installed, as well as the wxc_sdk using the pip tool. If you want to know more about virtual environments and pip, you can refer to the Python Packaging documentation.

    The other code already present in the file performs supporting tasks like setting up the logging infrastructure and contains comments to guide you through the process. If you are unfamiliar with Python and don't understand what these lines do, you can ignore them for now as they are not essential to the task of interacting with the Webex APIs.

    To use the SDK in this program, you must first import it by importing the WebexSimpleApi object from the wxc_sdk package. Throughtout this lab you will find examples like what is shown below that indicates the file you must edit, where in the file you should add code, and the code you should add. You can (and should) use the Copy button on the right to copy the selected line or lines and then paste them into your VS Code editor window in the correct location.

    In this example, you are looking for the line that says import logging and then adding the import statement on the next line as shown below. Paste the following into your file:

  5. The wxc_sdk documentation shows that the API is instantiated using the WebexSimpleApi class, which can optionally take a tokens parameter to specify the access token that will be used for accessing the Webex APIs. If the token is not specified here, then the SDK looks for a token in the local environment variable WEBEX_ACCESS_TOKEN. For this lab, you will be using a personal access token and passing it to the constructor for the class; however, in a production environment, you would likely inject the token into the environment variable and let the SDK obtain it automatically from there.

  6. Next you must obtain the personal access token. There are several ways to do this, but the easiest way is from any of the API documentation pages on developer.webex.com. In this case, you can use the List People API you executed previously. If the page indicates "Log in to try the API", sign in with pod6wbxuser@collab-api.com and password C1sco.123
  7. In the Authorization section, next to Bearer, click the copy icon then click OK on the box that appears.

  8. Switch back to VS Code and paste the personal access token you just copied to the personal_access_token line (replace ___PASTE_YOUR_PERSONAL_ACCESS_TOKEN_HERE___ and make sure it is still surrounded by the single quotes)

  9. Add the following line to instantiate the WebexSimpleApi object as "api" with this access token.

  10. You have an API object, but what can you do with it? In the Webex Documentation, you saw the Full API Reference section with all available APIs. Most of those will have a direct mapping to an API subpackage and method implemented in the SDK.

    The People API section in the Webex documentation has a corresponding PeopleApi subpackage in the wxc_sdk. This class has the methods list(), create(), details(), delete_person, update() and me(), each one corresponding to a Webex API method.

    Now repeat the GET List People query to search for a user with a specific email address, but this time using the SDK instead of the developer.webex.com page. Since the SDK was initialized as api in the previous step, you can perform the exact same query with api.people.list() and pass the email address as a parameter.

    Replace the email address in the email_to_search variable with pod6wbxuser@collab-api.com (make sure it is enclosed with quotes):

  11. Add the following line to query the Webex API for people with that email address. You can store the result in a list variable called webex_user_list. Even though querying for a single email address should only yield at most a single result (because email addresses in Webex must be unique), a list is always returned for list APIs.

    If you look carefully at the list() method in the documentation, the data type returned is technically a Generator. While generators have some advantages that are outside the scope of this lab, they can always be changed to a list, and we will do so in the lab to simplify the discussion. For more scalable applications, you should use the generator directly so that you can process the data as it is being returned instead of retrieving all of it before processing the data.

    It is worth spending a minute looking at this line in VSCode. If you hover over any portion of the api.people.list command, you will see the documentation and possible options. If you typed this command in manually, you would also get command-line completion.

  12. Try running your program to see what happens. You can do this by clicking the Run and Debug button in the left column.
  13. Once you click anywhere in list of "RUN AND DEBUG" configurations, You should see a predefined Configuration for running a python script named Python: wxc_enable_user.py in the list. Make sure it is selected:

  14. Click the green Start Debugging button left of the Python: wxc_enable_user.py text. Doing so launches a Terminal with the complete logging output at the bottom. If you scroll up a bit in that Terminal (you may need to resize to make it more visible) you will notice the debug level output from the SDK. The output shows you all the details of the request and response, including the verb, URI, and headers. This particular request has no body, but if it did have one, it would be shown as well. The response shows the status code (displayed at the top where it says Request 200[OK]) along with the headers and response body. You can see that the content type is application/json and the body is a JSON object with the user data. You were able to accomplish this with the single line of code you added to the program - api.people.list(email=email_to_search). This really shows the power of the SDK. You did not have to specify the URL, the headers, the method, or the body of the request. You simply called a method on the api.people object and passed the email address you wanted to search for and got back the results in JSON format.

  15. You may be wondering why the results of the API request and response are displayed on your terminal when the script does not explicitly have any lines saying print anything. You might expect to see a line that looks something like print(webex_user_list) in the program. The SDK uses the Python logging facility to output information. The logging.getLogger('wxc_sdk.rest').setLevel(logging.DEBUG) command in the script is setting the log level to DEBUG which triggers the SDK to log the raw messages for all requests and responses. If you changed this to logging.INFO, you would not see any of this output. We are therefore relying on the logging in the wxc_sdk instead of requiring explicit log statements. This is documented in the wxc_sdk documentation.

  16. The next task is to go over each item in the webex_user_list (there should only ever be at most one because there can only be one user with a particular email address in Webex) and log some data to the console using log.info(). Add the following code to the wxc_enable_user.py file as indicated below:

    This for loop iterates through each item in the webex_user_list and assigns it to the variable webex_user. The log.info() function is then called with webex_user as the argument. This will output the contents of the webex_user object to the console.

    The webex_user object which represents the single object returned by the SDK is not a simple Python data structure, but rather a custom one called Person in this case. This means you need to treat it differently than a simple Python dictionary as it is an object. If you are not familiar with the difference between the two, for the purposes of this lab you just need to remember that you access the attributes of an object using the dot operator (e.g. webex_user.display_name) rather than the square bracket notation used for dictionaries (e.g. webex_user['display_name']).

  17. To run the program again with the additional code, click Start Debugging again. You should see something that looks like this:

    The output is not the most readable. Although you can identify some things that look familiar based on the Webex Documentation, the fields do not exactly match what is in the API. The key is in the wxc_sdk documentation.

    This webex_user object is of a Person class, which gives it attributes like "person_id", "emails", "phone_numbers", etc. What this means, is that if, for example, you need to retrieve this object's display name, you would use webex_user.display_name. Generally speaking, the SDK simply converts the camelCase names from the API response to snake_case names in Python. This is a common practice in Python and is generally considered more readable. For example, the API response has a key called "displayName" which is converted to "display_name" in the Python object.
  18. Try printing just the object's display name. Replace the log.info(webex_user) line you previously entered with the following:

  19. Click Start Debugging

    You should see a line with "INFO __main__ User information found for" with the display name of the user with the queried email address.

  20. If you want to print all user data in a readable format (or pass the data to some other system that does not understand these custom Python classes) the class has a method called model_dump_json() that converts everything to simpler JSON, with its simpler data formats, effectively the same thing you would receive from running the API query from the Webex documentation.

    Once again replace the same line of code, but this time with the following:

    The Python logging capability is used for generating output instead of a simple print() because it allows us to control the level of output of not just our own code, but also see information from the underlying SDK, which uses the same logging facility. In fact, we have set the logging level for the underlying REST calls to DEBUG level, giving greater visibility into what is being sent and received.

  21. Click Start Debugging and examine the Terminal window output.

    If you look carefully, the data structure printed matches the Response Properties from the List People method in the Webex API specification exactly (including the keys "id", "emails", "phoneNumbers", "displayName", etc.).

    Pay attention to the output. Notice that the output is once again shown in camelCase, not the snake_case that the SDK's Python object uses. Keep this in mind if you ever decide to use the raw JSON returned by the model_dump_json() method. In this lab, we will use the Python object directly.
  22. This gives you a lot of information about a particular user, however to get all the settings, you need to use the api.people.details() method defined as follows in the SDK documentation:

    As seen in the documentation above, this method requires a person_id parameter. If you look at the output of your script, the webex_user that you populated earlier, being an instance of the Person class, has a person_id attribute. Therefore, you can pass the webex_user.person_id as the person_id parameter. Some additional information may be returned if you set the calling_data flag. To be sure, add this as follows:

  23. Click Start Debugging and examine the Terminal window output.

    The output will look basically the same as the previous user dump because, although you specified calling_data=True, there isn't any calling data at this time because calling is not enabled for this user yet. This time through you used the combination of the pformat method and the vars method to dump the object in a more readable format while preserving the snake_case names you must use if you want to access these properties. Printing a returned object in this way is a good way to understand what is being returned without having to look at the SDK documentation.

    You might also notice that the phone_numbers attribute is a list of PhoneNumber objects which are also defined in the SDK documentation. This is common with the SDK where you will see objects appear as properties of other objects. While this might seem complicated, once you start working with the SDK, you will find that it is very intuitive and easy to use.

Now that you have completed this basic exmple of using the wxc_sdk to interact with the Webex APIs and retrieve user information, we will move on to leveraging other methods to obtain the access tokens needed to interact with the Webex APIs in a way that is more secure and allows you to use the tokens for a longer period of time. If you recall, the personal access token is only valid for 12 hours. Additionally, you have pasted the token into the Python code which is not a best practice and is not secure.