As a starting point, there should be an API with a GET operation to retrieve (flight) data from a Cosmos DB. How the token can be generated to access the Cosmos DB was shown in the previous post Calculating CosmosDB API Token in API Management. The challenge here is that the API should provide different data fields, depending on whether it is one (free) or the other (business) product. In addition, only one of the products should evaluate the filters. Specifically, the scope is as follows:

FlightFreeFlightBusiness
Fieldsdirection,
date,
gate,
flightnumber
direction,
date,
gate,
flightnumber,
pilot,
baggageclaim
Filter
all flight data from the current day
FlightNumber,
FlightDay

The FlightFree product only delivers the 4 above-mentioned fields. A filter by flightnumber or date should be ignored, only all daily flights are delivered. With the FlightBusiness product, 2 additional pieces of information should be provided. All flight data is retrieved from the database, which can also be filtered for a day and/or a special flight number.

The actual query is product-specific. Therefore it is defined under the same variable name in the respective policy of the respective product. The policy for FlightBusiness defines the query-flights variable as follows:

<policies>
    <inbound>
        <set-variable name="query-flights" value="SELECT c.direction, c.date, c.gate, c.flightnumber, c.pilot, c.baggageclaim FROM c WHERE 1=1" />
        <base />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

The same variable is defined in the policy for FlightFree as follows:

<policies>
    <inbound>
        <set-variable name="query-flights" value="SELECT c.direction, c.date, c.gate, c.flightnumber FROM c WHERE c.date >= DateTimeFromParts(DateTimePart ('yyyy' , GetCurrentDateTime()), DateTimePart ('mm' , GetCurrentDateTime()), DateTimePart ('dd' , GetCurrentDateTime()))" />
        <base />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

A policy for All APIs and All operations is not necessary. The entire logic is in the policy of the operation for retrieving the flight data:

<policies>
    <inbound>
        <base />
        <set-variable name="cosmosQuery" value="@{
            JObject query = new JObject();
            string queryFromProduct = (string)context.Variables["query-flights"];
            if(context.Product.Name.Equals("FlightFree")){
                query.Add("query", queryFromProduct);
                return query.ToString(Newtonsoft.Json.Formatting.None);
            }
            
            string flightNumber = System.Net.WebUtility.UrlDecode(context.Request.OriginalUrl.Query.GetValueOrDefault("flightnumber"));
            string flightDay = System.Net.WebUtility.UrlDecode(context.Request.OriginalUrl.Query.GetValueOrDefault("flightday"));

            string where = String.Empty;
            Dictionary<string, Tuple<string, string>> config = new Dictionary<string, Tuple<string, string>>();      

            JArray parameters = new JArray();
            if (flightNumber != null)
            {
                config.Add("@flightNumber", Tuple.Create(" AND c.flightnumber = {0} ", flightNumber));
            }
            if (flightDay != null)
            {
                config.Add("@date", Tuple.Create(" AND STARTSWITH(c.date, {0} ) ", flightDay));
            }

            foreach(string key in config.Keys)
            {
                JObject prop = new JObject();
                prop.Add("name", key);
                prop.Add("value", config[key].Item2);
                where += String.Format(config[key].Item1, key);
                parameters.Add(prop);
            }

            query.Add("query", queryFromProduct + where.ToString());
            query.Add("parameters", parameters);
            return query.ToString(Newtonsoft.Json.Formatting.None);
        }" />
        <set-variable name="cosmosKey" value="{{comosDBReadKey}}" />
        <cache-lookup-value key="cachedUtcDate" variable-name="utcDateFromCache" />
        <cache-lookup-value key="cachedToken" variable-name="tokenFromCache" />
        <choose>
            <when condition="@(!context.Variables.ContainsKey("tokenFromCache") || !context.Variables.ContainsKey("utcDateFromCache"))">
                <set-variable name="utcDateFromCache" value="@{return DateTime.UtcNow.ToString("r");}" />
                <cache-store-value value="@((string)context.Variables["utcDateFromCache"])" key="cachedUtcDate" duration="300" />
                <set-variable name="authToken" value="@{
                    string date = (string)context.Variables["utcDateFromCache"];
                    byte[] key = Convert.FromBase64String((string)context.Variables["cosmosKey"]);
                    var hmacSha256 = new System.Security.Cryptography.HMACSHA256 { Key = key };
                    string payLoad = "post\ndocs\ndbs/airport/colls/flights\n"+date.ToLowerInvariant()+"\n\n";
                    byte[] hashPayLoad = hmacSha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(payLoad));
                    string signature = Convert.ToBase64String(hashPayLoad);
                    string token = System.Uri.EscapeDataString("type=master&ver=1.0&sig="+signature);
                    return token;
                }" />
                <cache-store-value value="@((string)context.Variables["authToken"])" key="cachedToken" duration="300" />
                <set-variable name="tokenFromCache" value="@((string)context.Variables["authToken"])" />
            </when>
            <otherwise />
        </choose>
        <set-variable name="requestPath" value="@((string)(context.Request.OriginalUrl.QueryString))" />
        <send-request mode="new" response-variable-name="response" timeout="10" ignore-error="false">
            <set-url>https://cosmosbyapim.documents.azure.com/dbs/airport/colls/flights/docs</set-url>
            <set-method>POST</set-method>
            <set-header name="Content-Type" exists-action="override">
                <value>application/query+json</value>
            </set-header>
            <set-header name="x-ms-documentdb-isquery" exists-action="override">
                <value>True</value>
            </set-header>
            <set-header name="Accept" exists-action="append">
                <value>application/json</value>
            </set-header>
            <set-header name="x-ms-version" exists-action="append">
                <value>2018-12-31</value>
            </set-header>
            <set-header name="x-ms-date" exists-action="append">
                <value>@((string)context.Variables["utcDateFromCache"])</value>
            </set-header>
            <set-header name="Authorization" exists-action="append">
                <value>@((string)context.Variables["tokenFromCache"])</value>
            </set-header>
            <set-header name="x-ms-max-item-count" exists-action="append">
                <value>10000</value>
            </set-header>
            <set-header name="x-ms-documentdb-query-enablecrosspartition" exists-action="override">
                <value>true</value>
            </set-header>
            <set-body>@((string)context.Variables["cosmosQuery"])</set-body>
        </send-request>
        <return-response>
            <set-body>@(((IResponse)context.Variables["response"]).Body.As<JObject>()["Documents"].ToString())</set-body>
        </return-response>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
        <!-- <set-header name="unwanted header" exists-action="delete" /> -->
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

The policy has the same structure and contains the same calculation of authentication as described in Article Calculating CosmosDB API Token in API Management. The integration of the query parameters is implemented from lines 4 to 40. Line 7 checks whether the FlightFree product has been used and then uses the submitted query directly. For other products, the query parameters are retrieved in lines 12 and 13 and saved in lines 21 and 25 as part of the where clause. The respective parameter is prepared and brought into the structure for Cosmos DB queries in lines 28 to 35.

Alternatives

It could also be divided into 2 operations. This means that one method does not have to evaluate or ignore the parameters, but instead there could be a pay and free method. The individual operations could then define the where clause by themselves.