Condiciones con variables de flujo

Esta página se aplica a Apigee y Apigee Hybrid.

Consulta la documentación de Apigee Edge.

Las sentencias condicionales son una estructura de control común en todos los lenguajes de programación. Al igual que un lenguaje de programación, la configuración del proxy de API admite sentencias condicionales para flujos, políticas, pasos y RouteRules. Con la definición de sentencias condicionales, se define el comportamiento dinámico de la API. Este comportamiento dinámico te permite realizar acciones como convertir XML en JSON solo para dispositivos móviles o enrutar a una URL de backend en función del tipo de contenido o el verbo HTTP del mensaje de la solicitud.

En este tema, se muestra cómo usar las sentencias para aplicar funciones de administración de API de forma dinámica en el entorno de ejecución sin escribir ningún código.

Configura sentencias condicionales

El comportamiento condicional se implementa en los proxies de API mediante una combinación de condiciones y variables. Una sentencia condicional se crea con un elemento de condición. La siguiente es una condición vacía:

<Condition></Condition>

Para crear una declaración condicional, agrega un operador condicional y una variable con la siguiente sintaxis:

<Condition>VARIABLE_NAME OPERATOR "VALUE"</Condition>

Por ejemplo:

<Condition>request.verb = "GET"</Condition>

Los operadores condicionales compatibles incluyen = (igual), != (no igual) y > (mayor que). Para facilitar la lectura, también puedes escribir los condicionales como texto: equals, notequals, greaterthan.

Cuando trabajas con rutas de URI, puedes usar ~/ o MatchesPath. También puedes hacer coincidir expresiones regulares de JavaRegex con el operador ~~.

Las condiciones se usan para definir los flujos condicionales del proxy de API sobre los recursos de API de backend, que se describen en Crea flujos condicionales a recursos de API de backend. Para obtener una lista completa de condicionales, consulta Referencia de las condiciones.

Variables

El trabajo de las condiciones es evaluar los valores de las variables. Una variable es una propiedad de una transacción HTTP ejecutada por un proxy de API, o una propiedad de una configuración de proxy de API en sí. Cuando un proxy de API recibe una solicitud de una aplicación, Apigee propaga una lista larga de variables que están asociadas con elementos como la hora del sistema, la información de red de la aplicación, los encabezados HTTP en los mensajes, la configuración del proxy de API, ejecuciones de políticas, etcétera. Esto crea un contexto enriquecido que puedes usar para configurar declaraciones condicionales.

Las variables siempre usan una notación de puntos. Por ejemplo, los encabezados HTTP del mensaje de solicitud están disponibles como variables llamadas request.header.HEADER_NAME. Por lo tanto, para evaluar el Content-type header, puedes usar la variable request.header.Content-type. Por ejemplo, request.header.Content-type = "application/json" indica que el tipo de contenido de la solicitud debe ser JSON.

Imagina que necesitas crear una sentencia condicional que haga que una política se aplique solo cuando el mensaje de solicitud sea GET. Para crear una condición que evalúe el verbo HTTP de una solicitud, crea la siguiente sentencia condicional. La variable de esta condición es request.verb. El valor de la variable es GET. El operador es =.

<Condition>request.verb = "GET"</Condition>

También puedes usar:

<Condition>request.verb equals "GET"</Condition>

Apigee usa esa sentencia para evaluar las condiciones. El ejemplo anterior se evalúa como verdadero si el verbo HTTP asociado con la solicitud es GET. Si el verbo HTTP asociado a la solicitud es POST, la declaración se evalúa como falsa.

Para habilitar el comportamiento dinámico, puedes adjuntar condiciones a los flujos, los pasos y las RouteRules.

Cuando adjuntas una condición a un flujo, creas un flujo condicional. Los flujos condicionales se ejecutan solo cuando la condición se evalúa como verdadera. Puedes adjuntar tantas políticas como desees a un flujo condicional. Un flujo condicional te permite crear reglas de procesamiento altamente especializadas para mensajes de solicitud o respuesta que cumplan determinados criterios.

Por ejemplo, para crear un flujo que se ejecute solo cuando el verbo de solicitud es GET:

<Flows>
  <Flow name="ExecuteForGETs">
  <Condition>request.verb="GET"</Condition>
  </Flow>
</Flows>

A fin de crear un flujo para solicitudes GET y otro para solicitudes POST, haz lo siguiente:

<Flows>
  <Flow name="ExecuteForGETs">
    <Condition>request.verb="GET"</Condition>
  </Flow>
  <Flow name="ExecuteForPOSTs">
    <Condition>request.verb="POST"</Condition>
  </Flow>
</Flows>

Como se muestra en el siguiente ejemplo, puedes aplicar la condición al paso de política en sí. La siguiente condición provoca que se aplique la política VerifyAPIKey solo si un mensaje de solicitud es un POST.

<PreFlow name="PreFlow">
    <Request>
        <Step>
            <Condition>request.verb equals "POST"</Condition>
            <Name>VerifyApiKey</Name>
        </Step>
    </Request>
</PreFlow>

Una vez que hayas definido esos flujos condicionales, puedes adjuntarles políticas, lo que permite que un proxy de API aplique un conjunto de políticas para las solicitudes GET y otro conjunto de políticas para las solicitudes POST.

Para obtener información de referencia completa, consulta los siguientes recursos:

Ejemplo 1

En el siguiente ejemplo, se muestra un solo flujo condicional llamado Convert-for-devices, configurado en el flujo de respuesta de ProxyEndpoint. Agrega la condición como elemento en la entidad a la que se aplica la condición. En este ejemplo, la condición es un componente del flujo. Por lo tanto, el flujo se ejecutará cada vez que la sentencia se evalúe como true.

<Flows>
  <Flow name="Convert-for-devices">
  <Condition>(request.header.User-Agent = "Mozilla")</Condition>
    <Response>
      <Step><Name>ConvertToJSON</Name></Step>
    </Response>
  </Flow>
</Flows>

Para cada solicitud recibida de una app, Apigee almacena los valores de todos los encabezados HTTP presentes como variables. Si la solicitud contiene un encabezado HTTP llamado User-Agent, ese encabezado y su valor se almacenan como una variable llamada request.header.User-Agent.

Dada la configuración del ProxyEndpoint anterior, Apigee verifica el valor de la variable request.header.User-Agent para ver si la condición se evalúa como verdadera.

Si la condición se evalúa como true, es decir, el valor de la variable request.header.User-Agent es igual a Mozilla, entonces se ejecuta el flujo condicional y se aplica la política XMLtoJSON llamada ConvertToJSON. De lo contrario, el flujo no se ejecuta y la respuesta XML se muestra sin modificar (en formato XML) a la app solicitante.

Ejemplo 2

Veamos un ejemplo específico en el que necesitas transformar el mensaje de respuesta de XML a JSON, pero solo para dispositivos móviles. Primero, crea la política que convertirá la respuesta con formato XML de la API de Weather a JSON:

<XMLToJSON name="ConvertToJSON">
  <Options>
  </Options>
  <OutputVariable>response</OutputVariable>
  <Source>response</Source>
</XMLToJSON>

La configuración de política anterior indica al proxy de la API que tome el mensaje de respuesta, realice una conversión de XML a JSON con la configuración predeterminada y, luego, escriba el resultado en el nuevo mensaje de respuesta. Si quieres convertir un mensaje request de XML a JSON, solo debes establecer ambos valores como request.

Dado que deseas convertir las respuestas de XML a JSON, debes configurar un flujo de respuesta condicional para realizar la conversión. Por ejemplo, para convertir todas las respuestas de XML a JSON antes de que se muestren en la aplicación cliente, configura el siguiente flujo de respuesta ProxyEndpoint.

<Flows>
  <Flow name="Convert-for-devices">
    <Response>
      <Step><Name>ConvertToJSON</Name></Step>
    </Response>
  </Flow>
</Flows>

Cuando invocas la API mediante la solicitud estándar, la respuesta tiene el formato JSON.

Sin embargo, tu objetivo solo es convertir los informes de Weather a JSON cuando el cliente solicitante es un dispositivo móvil. Para habilitar este comportamiento dinámico, debes agregar una sentencia condicional al flujo.

Prueba el flujo condicional

En esta solicitud de muestra, el encabezado HTTP User-Agent se establece en Mozilla, lo que hace que la sentencia condicional se evalúe como verdadera y el flujo condicional Convert-for-devices se ejecute.

curl -H "User-Agent:Mozilla" http://example.com/weather/forecastrss?w=12797282

O hace que se imprima con formato estilístico si Python está disponible:

curl -H "User-Agent:Mozilla" http://example.com/weather/forecastrss?w=12797282 | python -mjson.tool

Respuesta de muestra:

. . .

"yweather_forecast": [
   {
      "code": "11",
      "date": "12 Dec 2012",
      "day": "Wed",
      "high": "55",
      "low": "36",
      "text": "Showers"
    },
    {
      "code": "32",
      "date": "13 Dec 2012",
      "day": "Thu",
      "high": "56",
      "low": "38",
      "text": "Sunny"
    }
  ]
}

. . .

Una solicitud enviada sin el encabezado User-Agent o con un valor diferente a Mozilla, generará una respuesta con formato XML.

$ curl http://example.com/weather/forecastrss?w=12797282

Se muestra la respuesta XML sin modificar.

Respuesta de muestra:

<yweather:forecast day="Wed" date="12 Dec 2012" low="36" high="55" text="Showers" code="11" /> <yweather:forecast day="Thu" date="13 Dec 2012" low="38" high="56" text="Sunny" code="32" />

Coincidencia de patrones

En esta sección, se describe cómo usar la coincidencia de patrones con condiciones en un flujo de Apigee.

Operadores

En esta sección, se describe cómo usar los siguientes operadores de coincidencia de patrones en las sentencias condicionales:

Coinciden

Primero, analicemos el operador condicional Matches o ~. Estos dos operadores son iguales: la versión en inglés, Matches, se considera una opción más legible.

Resumen: El operador Matches te brinda dos posibilidades. Puedes hacer coincidir la string de forma literal o hacer coincidir un comodín con *. Como es de esperar, el comodín coincide con cero o más caracteres. Veamos cómo funciona este proceso.

El siguiente XML muestra una condición de paso. Ejecuta la política SomePolicy cuando la condición se evalúa como verdadera. En este ejemplo, probamos la variable proxy.pathsuffix, una variable integrada en Apigee que almacena el sufijo de ruta de la solicitud. Sin embargo, ten en cuenta que puedes probar el valor de cualquier variable de flujo que contenga una string. Por lo tanto, en este caso, si la ruta base de la solicitud entrante es /animals y la solicitud es /animals/cat, el sufijo de la ruta es la string literal /cat.

<PreFlow name="PreFlow">
  <Request>
    <Step>
      <Condition>(proxy.pathsuffix Matches "/cat")</Condition>
      <Name>SomePolicy</Name>
    </Step>
  </Request>
  <Response/>
</PreFlow>

Pregunta: ¿Qué sufijo de ruta del proxy hará que se ejecute SomePolicy? Solo hay una posibilidad.

Llamada a la API:

GET http://example.com/matchtest/cat

¿La política se ejecuta? Sí, porque el sufijo de la ruta del proxy coincide con /cat de manera exacta. No se ejecutará si el sufijo es /bat, /dog, / o cualquier otro.

Ahora, considera esta sentencia condicional en la que usamos el carácter comodín *:

<Condition>(proxy.pathsuffix Matches "/*at")</Condition>

Llamada a la API:

GET http://example.com/matchtest/cat

¿La política se ejecuta? Sí, porque el comodín coincide con cualquier carácter y "/cat" es una coincidencia.

Llamada a la API:

GET http://example.com/matchtest/bat

¿La política se ejecuta? Sí, porque el comodín coincide con cualquier carácter y "/bat" es una coincidencia.

Llamada a la API:

GET http://example.com/matchtest/owl

¿La política se ejecuta? No. Aunque el comodín coincide con o, las letras wl no coinciden.

Ahora, movamos el comodín al final del sufijo:

<Condition>(proxy.pathsuffix Matches "/cat*")</Condition>

Llamada a la API:

GET http://example.com/matchtest/cat

¿La política se ejecuta? Sí, porque el comodín coincide con cero o más caracteres de cualquier tipo.

Llamada a la API:

GET http://example.com/matchtest/bat

¿La política se ejecuta? No, /bat no es una coincidencia.

Llamada a la API:

GET http://example.com/matchtest/cat123

¿La política se ejecuta? Sí, el comodín coincide con cero o más caracteres, por lo que 123 produce una coincidencia.

Llamada a la API:

GET http://example.com/matchtest/cat/bird/mouse

¿La política se ejecuta? Sí, porque el comodín coincide con cero o más caracteres, por lo que /bird/mouse produce una coincidencia. Ten en cuenta que una expresión como esta puede causar problemas, ya que coincide con todo lo que se encuentra después de los caracteres literales.

Pregunta: ¿El operador Matches distingue mayúsculas de minúsculas?

Sí. Supongamos que tienes una condición como la que se muestra a continuación:

<Condition>(proxy.pathsuffix Matches "/*At")</Condition>

Llamada a la API:

GET http://example.com/matchtest/cat

¿La política se ejecuta? No, el comodín coincide con cualquier letra (sin importar las mayúsculas), pero la a minúscula no coincide con A.

Llamada a la API:

GET http://example.com/matchtest/bAt

¿La política se ejecuta? Sí, las mayúsculas coinciden.

Pregunta: ¿Cómo puedo escapar caracteres con el operador Matches?

Usa el carácter de porcentaje % para escapar los caracteres reservados. Por ejemplo:

<Condition>(proxy.pathsuffix Matches "/c%*at")</Condition>

Llamada a la API:

GET http://example.com/matchtest/cat

¿La política se ejecuta? No, el operador Matches busca la string literal c*at.

Llamada a la API:

GET http://example.com/matchtest/c*at

Pregunta: ¿La política se ejecuta?

Sí, esta ruta coincide, pese a ser algo inusual.

JavaRegex

Como puedes ver, el operador Matches es excelente para situaciones simples. Sin embargo, puedes usar el operador JavaRegex o ~~. Estos dos son el mismo operador, pero se considera que JavaRegex es más legible. Se llama JavaRegex porque permite la coincidencia de patrones de expresión regular, y Apigee sigue las mismas reglas que las clases del paquete java.util.regex en el lenguaje Java. El operador JavaRegex funciona de manera muy diferente del operador Matches, por lo que es importante no confundirlos.

Resumen: El operador JavaRegex te permite usar la sintaxis de expresiones regulares en las sentencias condicionales.

El siguiente código muestra una condición de paso. Ejecuta la política AnyPolicy si la condición se evalúa como true. En este ejemplo, probamos la variable proxy.pathsuffix, una variable integrada en Apigee que almacena el sufijo de la ruta de acceso de la solicitud. Si la ruta base de la solicitud entrante es /animals y la solicitud es /animals/cat, el sufijo de la ruta es la string literal /cat.

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix JavaRegex "/cat")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

Pregunta: ¿Qué sufijo de ruta del proxy hará que se ejecute SomePolicy? Al igual que con el operador Matches, solo hay una posibilidad en este caso.

Llamada a la API:

GET http://example.com/matchtest/cat

¿La política se ejecuta? Sí, porque el sufijo de la ruta del proxy coincide con /cat de manera exacta. No se ejecutará si el sufijo es /bat, /dog, o cualquier otro.

Ahora, creemos una expresión regular con el cuantificador *. Este cuantificador coincide con cero o más ocurrencias de los caracteres anteriores.

<Condition>(proxy.pathsuffix JavaRegex "/c*t")</Condition>

Llamada a la API:

GET http://example.com/matchtest/cat

¿La política se ejecuta? No. El cuantificador * coincide con cero o más ocurrencias del carácter anterior, que es una c.

Llamada a la API:

GET http://example.com/matchtest/ccccct

¿La política se ejecuta? Sí, porque el comodín coincide con cero o más ocurrencias del carácter anterior.

A continuación, usamos el cuantificador ?, que coincide con el carácter anterior una vez o nada.

<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>

Llamada a la API:

GET http://example.com/matchtest/cat

¿La política se ejecuta? Sí. El cuantificador ? coincide con cero o una ocurrencia del carácter anterior, que es una a.

Llamada a la API:

GET http://example.com/matchtest/ct

¿La política se ejecuta? Sí. El cuantificador ? coincide con uno o ninguno de los caracteres anteriores. En este caso, no hay caracteres a, por lo que la condición se evalúa como true.

Llamada a la API:

GET http://example.com/matchtest/caat

¿La política se ejecuta? No. El cuantificador ? coincide con una ocurrencia del carácter anterior, que es una a.

Luego, usamos el estilo [abc] o de agrupación de la expresión de regex. Coincide con los caracteres a, b o c.

<Condition>(proxy.pathsuffix JavaRegex "/[cbr]at")</Condition>

Llamada a la API:

GET http://example.com/matchtest/cat

¿La política se ejecuta? Sí. Usamos expresiones regulares aquí, y la expresión [cbr] coincide con c, b o r. Estas llamadas también coinciden:

GET http://example.com/matchtest/bat

GET http://example.com/matchtest/rat

Pero esto no es una coincidencia:

GET http://example.com/matchtest/mat

Pregunta: ¿El operador JavaRegex distingue mayúsculas de minúsculas?

Sí. Supongamos que tienes una condición como la que se muestra a continuación:

<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>

Llamada a la API:

GET http://example.com/matchtest/cat

¿La política se ejecuta? Sí, la regex coincide con cero o una ocurrencia del carácter anterior, que es a.

Llamada a la API:

GET http://example.com/matchtest/cAt

Pregunta: ¿La política se ejecuta?

No, porque la A mayúscula no coincide con la a minúscula.

MatchesPath

El operador MatchesPath también se puede especificar como ~/. Se parece a los operadores Matches (~) y JavaRegex (~~). Sin embargo, MatchesPath es completamente diferente.

Solo recuerda que este operador considera una ruta de acceso como una serie de partes. Por lo tanto, si la ruta de acceso es /animals/cats/wild, esta constaría de las partes /animals, /cats y /wild.

El operador MatchesPath te permite usar dos notaciones de comodín: un solo asterisco (*) y un doble asterisco (**). El asterisco único coincide con un elemento de ruta. El doble asterisco coincide con uno o varios elementos de ruta.

Veamos un ejemplo. En este ejemplo, probamos la variable proxy.pathsuffix, una variable integrada en Apigee que almacena el sufijo de ruta de la solicitud. Sin embargo, ten en cuenta que puedes probar el valor de cualquier variable de flujo que contenga una string.

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/*")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

Pregunta: ¿Qué sufijo de ruta del proxy hará que se ejecute SomePolicy?

Llamada a la API:

GET http://example.com/matchtest/animals

Pregunta: ¿La política se ejecuta?

No, porque la condición exige otro elemento de ruta después de /animals, como lo especifica /*.

Llamada a la API:

GET http://example.com/matchtest/animals/

¿La política se ejecuta? Sí, la ruta de acceso tiene otro elemento de ruta (la parte después de /animals/), pero solo está vacío.

Llamada a la API:

GET http://example.com/matchtest/animals/cats

¿La política se ejecuta? Sí, porque claramente la ruta de acceso tiene un elemento (/cats) después de /animals.

Llamada a la API:

GET http://example.com/matchtest/animals/cats/wild

Pregunta: ¿La política se ejecuta?

No, porque el asterisco solo coincide con un elemento de ruta, y esta API tiene más de un elemento después de /animals.

Ahora, usemos el asterisco doble:

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/**")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

Pregunta: ¿Qué sufijo de ruta del proxy hará que se ejecute SomePolicy?

Llamada a la API:

GET http://example.com/matchtest/animals

¿La política se ejecuta? No, porque la condición exige al menos un elemento de ruta a continuación, como lo especifica /**.

Llamada a la API:

GET http://example.com/matchtest/animals/

¿La política se ejecuta?

Sí, la ruta de acceso tiene otro elemento de ruta (la parte después de /animals/), pero solo está vacío.

Llamada a la API:

GET http://example.com/matchtest/animals/cats

¿La política se ejecuta?

Sí, porque la ruta de acceso tiene al menos un elemento después de /animals

Llamada a la API:

GET http://example.com/matchtest/animals/cats/wild

¿La política se ejecuta?

Sí, porque la ruta tiene más de un elemento después de /animals

Mezcla asteriscos

Puedes usar combinaciones del asterisco simple (*) y doble (**) para definir mejor la coincidencia de rutas.

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/*/wild/**")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

Llamada a la API:

Todas estas llamadas a la API producirán una coincidencia:

GET http://example.com/matchtest/animals/cats/wild/

y

GET http://example.com/matchtest/animals/dogs/wild/austrailian

y

GET http://example.com/matchtest/animals/birds/wild/american/finches

Recursos de la API

Los servicios RESTful son colecciones de recursos de API. Un recurso de API es un fragmento de ruta de URI que identifica algunas entidades a las que los desarrolladores pueden acceder mediante una llamada a tu API. Por ejemplo, si tu servicio proporciona informes y pronósticos del clima, tu servicio de backend podría definir dos recursos de API:

  • http://mygreatweatherforecast.com/reports
  • http://mygreatweatherforecast.com/forecasts

Cuando creas un proxy de API (como se muestra en Compila tu primer proxy de API), como mínimo, creas una URL base de alias que se asigna a tu servicio de backend. Por ejemplo:

URL base del backend URL del proxy de API nueva o equivalente
http://mygreatweatherforecast.com http://example.com/mygreatweatherforecast

En este punto, puedes realizar llamadas a la API de tu backend mediante la URL base. Sin embargo, cuando usas la URL del proxy de API, las cosas ser vuelven interesantes.

Además de las estadísticas de API que Apigee comienza a recopilar cuando usas el proxy de API, los proxies también te permiten definir flujos condicionales que se asignan a los recursos en tu backend. En esencia, si llega una llamada GET al recurso /reports, Apigee debería hacer algo.

En la imagen siguiente, se muestra la diferencia de comportamiento entre dos URL que acceden al mismo backend. Una es la URL del recurso sin proxy. El otro es un proxy de API de Apigee con un flujo condicional al mismo recurso de backend. A continuación, describiremos los flujos condicionales con más detalle.

Para la URL del proxy de API de Apigee con un flujo condicional, la respuesta convierte el XML en JSON y recopila estadísticas.

Cómo asignar proxies de API a recursos de backend específicos

Con una URL de proxy de API asignada a la URL base del servicio de backend (cuando creas el proxy), puedes agregar flujos condicionales a recursos específicos, como los recursos /reports y /forecasts que se mencionó anteriormente.

Supongamos que quieres que Apigee haga algo cuando las llamadas llegan a los recursos /reports o /forecasts. En este punto, no le indicas a Apigee qué hacer, solo que debe escuchar las llamadas a esos recursos. Esto se hace con las condiciones. En tu proxy de API de Apigee, puedes crear flujos condicionales para /reports y /forecasts. Para fines conceptuales, el siguiente XML del proxy de API muestra cómo podrían ser esas condiciones.

<Flows>
    <Flow name="reports">
        <Description/>
        <Request/>
        <Response/>
        <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition>
    </Flow>
    <Flow name="forecasts">
        <Description/>
        <Request/>
        <Response/>
        <Condition>(proxy.pathsuffix MatchesPath "/forecasts") and (request.verb = "GET")</Condition>
    </Flow>
</Flows>

Esas condiciones dicen: Cuando una solicitud GET viene con /reports y /forecasts en la URL, Apigee hará todo lo que tú (el desarrollador de la API) le indicas, a través de las políticas que adjuntas a esos flujos.

Este es un ejemplo de cómo indicarle a Apigee lo que debe hacer cuando se cumple una condición. En el siguiente XML del proxy de API, cuando se envía una solicitud GET a https://example.com/mygreatweatherforecast/reports, Apigee ejecuta la política XML-to-JSON-1 en la respuesta.

<Flows>
  <Flow name="reports">
    <Description/>
    <Request/>
    <Response>
      <Step>
        <Name>XML-to-JSON-1</Name>
      </Step>
    </Response>
  <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition>
</Flow>

Además de esos flujos condicionales, cada proxy de API también incluye dos flujos predeterminados: un <PreFlow> que se ejecuta antes de tus flujos condicionales y un <PostFlow> que se ejecuta después de los flujos condicionales. Esos son útiles para ejecutar políticas cuando se realiza cualquier llamada a un proxy de API. Por ejemplo, si deseas verificar la clave de API de una app con cada llamada, sin importar el recurso de backend al que se accede, puedes colocar una política de verificación de la clave de API en <PreFlow>. Para obtener más información sobre los flujos, consulta Configura flujos.

Crea flujos condicionales a recursos de backend

Definir flujos condicionales en los recursos de backend de un proxy de API es completamente opcional. Sin embargo, esos flujos condicionales te permiten aplicar una administración y supervisión detalladas.

con el que podrás:

  • Aplicar la administración, de manera que refleje la semántica de tu modelo de API
  • Aplicar políticas y comportamiento con secuencias de comandos a rutas de recursos individuales (URI)
  • Recopilar métricas detalladas para los servicios de Analytics

Por ejemplo, imagina que debes aplicar tipos diferentes de lógica a tus backend /developers a los recursos /apps.

Para hacerlo, debes agregar dos flujos condicionales en tu proxy de API: /developers y /apps.

Editor de proxies nuevo

Para agregar un flujo condicional, haz lo siguiente:

  1. Selecciona la pestaña Desarrollo (Develop) en el Editor de proxies.
  2. Selecciona Extremos de proxy > predeterminado (Proxy endpoints > default) en el panel izquierdo.

    predeterminado (Proxy endpoints > default) en el panel de la izquierda." class="l10n-absolute-url-src screenshot" l10n-attrs-original-order="class,width,alt,src" src="https://cloud.google.com/static/apigee/docs/api-platform/fundamentals/images/proxy-endpoints-default.png" width="35%" />

  3. Haz clic en el botón + encima del panel Respuesta (Response).

    Botón para agregar un flujo condicional

  4. En el diálogo Agregar flujo condicional, ingresa las siguientes configuraciones:
    • Nombre del flujo: Developers
    • Tipo de condición: Path
    • Ruta: /developers

    Cuadro de diálogo Agregar flujo condicional.

    La condición se activará (y se ejecutarán políticas) si se envía una llamada al proxy con /developers al final del URI.

  5. Ahora, agrega un flujo condicional para /apps y supongamos que deseas que la condición se active en el URI y el verbo POST en una solicitud. Debes aplicar la siguiente configuración:
    • Nombre del flujo: Apps
    • Tipo de condición: Path and Verb
    • Ruta: /apps
    • Verbo: POST

    La condición se activará (y se ejecutarán las políticas) si se envía una llamada al proxy con /apps al final del URI y un verbo POST.

Los flujos agregados se muestran en el panel Respuesta:

Cuadro de diálogo Agregar flujo condicional.

Editor de proxies clásico

En el panel Desarrollar del panel Navegador del proxy de API, haz clic en junto a predeterminado en los Extremos de proxy.

Cuando mantienes el puntero sobre el signo más junto a la configuración predeterminada, el texto flotante dice Agregar flujo nuevo.

En la ventana Nuevo flujo condicional, ingresa la configuración clave siguiente:

  • Nombre del flujo: Developers
  • Tipo de condición: Path
  • Ruta: /developers

En el panel Flujo condicional nuevo, se configura un flujo llamado Desarrolladores que tiene la descripción “Desarrolladores de app registrados con Servicios para desarrolladores”.

La condición se activará (y se ejecutarán políticas) si se envía una llamada al proxy con /developers al final del URI.

Ahora, agrega un flujo condicional para /apps y supongamos que deseas que la condición se active en el URI y el verbo POST en una solicitud. Debes aplicar la siguiente configuración:

  • Nombre del flujo: Apps
  • Tipo de condición: Path and Verb
  • Ruta: /apps
  • Verbo: POST

En el panel Nuevo flujo condicional, se configura un flujo llamado Apps con la descripción "Apps de desarrollador registradas en Servicios para desarrolladores".

La condición se activará (y se ejecutarán las políticas) si se envía una llamada al proxy con /apps al final del URI y un verbo POST.

En el panel Navegación, verás nuevos flujos para Apps y Desarrolladores.

Los flujos nuevos para Apps y Desarrolladores se muestran en el panel Navegación en Extremos de proxy.

Selecciona uno de los flujos para ver la configuración de flujo condicional en la vista de código del editor de proxy de API:

<Flow name="Apps">
    <Description>Developer apps registered in Developer Services</Description>
    <Request/>
    <Response/>
    <Condition>(proxy.pathsuffix MatchesPath "/apps") and (request.verb = "POST")</Condition>
</Flow>

Como puedes ver, los recursos de API son simplemente flujos condicionales que evalúan la ruta de URI de la solicitud entrante. (La variable proxy.pathsuffix identifica el URI de la solicitud que sigue a la BasePath configurada en la configuración de ProxyEndpoint).

Cada recurso de API que definas se implementa mediante un flujo condicional en el proxy de API. (Consulta Configura flujos).

Una vez que implementes el proxy de API en el entorno de prueba, ocurrirá lo siguiente con esta solicitud:

http://example.com/PROXY_PATH/apps

hará que la condición se evalúe como true y se ejecutará este flujo junto con todas las políticas asociadas.

En la siguiente condición de ejemplo, se usa una expresión regular de Java para reconocer las llamadas realizadas al recurso /apps con o sin una barra diagonal final (/apps o /apps/**):

<Condition>(proxy.pathsuffix JavaRegex "/apps(/?)") and (request.verb = "POST")</Condition>

Para obtener más información sobre este tipo de condición, consulta Cómo hacer coincidir todas las versiones, sin importar si hay una "/" final… en la comunidad de Apigee.

Modela URI jerárquicos

En algunos casos, tendrás recursos de API jerárquicos. Por ejemplo, la API de lista de apps del desarrollador proporciona un método para enumerar todas las apps que pertenecen a un desarrollador. Esta es la ruta del URI:

/developers/DEVELOPER_EMAIL/apps

Es posible que tengas recursos en los que se genere un ID único para cada entidad de una colección, lo que a veces se anota de la siguiente manera:

/genus/:id/species

Esta ruta se aplica de la misma manera a los siguientes dos URI:

/genus/18904/species
/genus/17908/species

Para representar esta estructura en un recurso de API, puedes usar comodines. Por ejemplo:

/developers/*/apps
/developers/*example.com/apps
/genus/*/species

Estos resolverán los URI jerárquicos como recursos de API de forma adecuada.

En algunos casos, en especial para las API muy jerárquicas, es posible que desees resolver todo debajo de un fragmento de URI determinado. Para hacerlo, usa un comodín de asterisco doble en la definición del recurso. Por ejemplo, si defines el siguiente recurso de API:

/developers/**

Ese recurso de API resolverá las siguientes rutas de URI:

/developers/DEVELOPER_EMAIL/apps
/developers/DEVELOPER_EMAIL/keys
/developers/DEVELOPER_EMAIL/apps/APP_ID/keys

Así se vería la condición del flujo condicional en la definición del proxy de API:

<Condition>(proxy.pathsuffix MatchesPath "/developers/**") and (request.verb = "POST")</Condition>

Más ejemplos

Condición adjunta a RouteRule

<RouteRule name="default">
  <!--this routing executes if the header indicates that this is an XML call. If true, the
    call is routed to the endpoint XMLTargetEndpoint-->
  <Condition>request.header.content-type = "text/xml"</Condition>
  <TargetEndpoint>XmlTargetEndpoint</TargetEndpoint>
</RouteRule>

Condición adjunta a una política

<Step>
  <!--the policy MaintenancePolicy only executes if the response status code is exactly 503 -->
  <Condition>response.status.code = 503</Condition>
  <Name>MaintenancePolicy</Name>
</Step>

Flujo condicional

<!-- this entire flow is executed only if the request verb is a GET-->
<Flow name="GetRequests">
  <Condition>request.verb="GET"</Condition>
  <Request>
    <Step>
<!-- this policy only executes if request path includes a term like statues-->
<Condition>request.path ~ "/statuses/**"</Condition>
      <Name>StatusesRequestPolicy</Name>
    </Step>
  </Request>
  <Response>
    <Step>
<!-- this condition has multiple expressions. The policy executes if the response code status is exactly 503 or 400-->
<Condition>(response.status.code = 503) or (response.status.code = 400)</Condition>
      <Name>MaintenancePolicy</Name>
    </Step>
  </Response>
</Flow>

Ejemplos de operadores en condiciones

Estos son algunos ejemplos de operadores que se usan para crear condiciones:

  • request.header.content-type = text/xml
  • request.header.content-length < 4096 && request.verb = PUT
  • response.status.code = 404 || response.status.code = 500
  • request.uri MatchesPath /*/statuses/**
  • request.queryparam.q0 NotEquals 10

Un ejemplo práctico: Ignora / al final de una ruta de acceso

Los desarrolladores de Apigee comúnmente quieren manejar estos dos sufijos de ruta: /cat y /cat/. Esto se debe a que algunos usuarios o clientes pueden llamar a tu API con la barra adicional al final de la ruta de acceso, y debes ser capaz de controlarla esto en tus declaraciones condicionales. Este caso práctico exacto se analiza en Cómo hacer coincidir sin importar si hay una "/" al final de la URL….

Si lo prefieres, puedes lograrlo sin usar Regex, de la siguiente manera:

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>((proxy.pathsuffix = "/cat") OR (proxy.pathsuffix = "/cat/")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

Esta es una buena opción. Es claro y legible.

Sin embargo, puedes hacer lo mismo con Regex como este. Los paréntesis se usan para agrupar la parte de regex de la declaración, pero no son obligatorios.

<Condition>(proxy.pathsuffix JavaRegex "/cat(/?)"</Condition>

Llamadas a la API:

GET http://example.com/matchtest/cat
or
GET http://example.com/matchtest/cat/

¿La política se ejecuta? Sí. Ten en cuenta que en una expresión regular, el carácter ? significa: coincidir con cero o uno de los caracteres anteriores. Por lo tanto, /cat y /cat/ son coincidencias.

Llamada a la API:

GET http://example.com/matchtest/cat/spotted

¿La política se ejecuta? No. La expresión regular coincide con cero o una ocurrencia del carácter anterior y no se permite nada más.

Haz coincidir strings arbitrarias con JavaRegex

En todos los ejemplos de este tema, se muestra cómo hacer coincidir una de las variables de flujo integradas: proxy.pathsuffix. Es bueno saber que puedes realizar una coincidencia de patrones en cualquier variable de flujo o string arbitraria, ya sea una variable de flujo integrada como proxy.pathsuffix o no.

Por ejemplo, si tienes una condición que prueba una string arbitraria, tal vez una string que se muestra en una carga útil de backend, o una string que se muestra en una búsqueda del servidor de autenticación, puedes usar operadores coincidentes para probarla. Si usas JavaRegex, la expresión regular se comparará con toda la string del asunto. Si el asunto es abc y la expresión regular es [a-z], no hay coincidencia, porque [a-z] coincide exactamente con un carácter Alfa. La expresión [a-z]+ funciona, al igual que [a-z]* y [a-z]{3}.

Revisemos un ejemplo concreto. Supongamos que el servidor de autenticación muestra una lista de roles como una string separada por comas: editor, author, guest.

Para probar la presencia del rol de editor, esta construcción no funcionará, porque editor solo es parte de la string completa.

<Condition>returned_roles ~~ "editor"</Condition>

Sin embargo, esta construcción funcionará:

<Condition>returned_roles ~~ ".*\beditor\b.*")</Condition>

Funciona porque tiene en cuenta los saltos de palabra y cualquier otra parte de la string con el prefijo y el sufijo .*.

En este ejemplo, también puedes probar editor con el operador Matches:

<Condition>returned_roles ~~ "*editor*")</Condition>

Sin embargo, JavaRegex suele ser una mejor opción si necesitas más precisión.

Escapa comillas dobles en las expresiones de JavaRegex

La sintaxis de condición exige que una expresión de JavaRegex esté entre comillas dobles. Por lo tanto, si tienes una expresión de regex que incluye comillas dobles, necesitas una forma alternativa de hacerlas coincidir. La respuesta es Unicode. Por ejemplo, supongamos que pasas un encabezado que incluye comillas dobles, como el siguiente:

 -H 'content-type:multipart/related; type="application/xop+xml"'

Si intentas hacer coincidir ese encabezado con una condición de regex, recibirás un error Invalid Condition porque la expresión incluye las comillas dobles:

request.header.Content-Type ~~ "(multipart\/related)(; *type="application\/xop\+xml\")"

La solución es reemplazar las comillas dobles basadas en ASCII por su equivalente de Unicode, \u0022. Por ejemplo, la siguiente expresión es válida y produce el resultado esperado:

request.header.Content-Type ~~ "(multipart\/related)(; *type=\u0022application\/xop\+xml\u0022)"