def build_api_url(
        cls, path, query_params=None, api_base_url=None, api_version=None
    ):
        """Construct an API url given a few components, some optional.

        Typically, you shouldn't need to use this method.

        :type path: str
        :param path: The path to the resource (ie, ``'/b/bucket-name'``).

        :type query_params: dict or list
        :param query_params: A dictionary of keys and values (or list of
                             key-value pairs) to insert into the query
                             string of the URL.

        :type api_base_url: str
        :param api_base_url: The base URL for the API endpoint.
                             Typically you won't have to provide this.

        :type api_version: str
        :param api_version: The version of the API to call.
                            Typically you shouldn't provide this and instead
                            use the default for the library.

        :rtype: str
        :returns: The URL assembled from the pieces provided.
        """
        url = cls.API_URL_TEMPLATE.format(
            api_base_url=(api_base_url or cls.API_BASE_URL),
            api_version=(api_version or cls.API_VERSION),
            path=path,
        )

        query_params = query_params or {}
        if query_params:
            url += "?" + urlencode(query_params, doseq=True)

        return url