Esta página se aplica a Apigee y Apigee Hybrid.
Consulta la documentación de
Apigee Edge.
Las instrucciones condicionales son una estructura de control habitual en todos los lenguajes de programación. Al igual que un lenguaje de programación, la configuración del proxy de API admite instrucciones condicionales para Flows, Policies, Steps y RouteRules. Al definir instrucciones condicionales, puedes definir el comportamiento dinámico de tu API. Este comportamiento dinámico te permite hacer cosas 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 del verbo HTTP del mensaje de solicitud.
En este tema se explica cómo usar las condiciones para aplicar dinámicamente las funciones de gestión de APIs en el tiempo de ejecución sin escribir código.
Configurar instrucciones condicionales
El comportamiento condicional se implementa en los proxies de API mediante una combinación de condiciones y variables. Las instrucciones condicionales se crean con un elemento Condition. A continuación, se muestra un ejemplo de condición vacía:
<Condition></Condition>
Para crear una instrucción condicional, añade un operador condicional y una variable con la siguiente sintaxis:
<Condition>VARIABLE_NAME OPERATOR "VALUE"</Condition>
Por ejemplo:
<Condition>request.verb = "GET"</Condition>
Entre los operadores condicionales admitidos se incluyen =
(igual a), !=
(distinto de) y >
(mayor que). Para que sea más fácil de leer, también puedes escribir las condicionales como
texto: equals
, notequals
, greaterthan
.
Cuando trabajes con rutas de URIs, puedes usar ~/
o MatchesPath
. También puedes
hacer coincidir expresiones regulares de JavaRegex con el operador ~~
.
Las condiciones se usan para definir flujos condicionales de proxies de API a recursos de APIs backend, tal como se describe en el artículo Crear flujos condicionales a recursos de APIs backend. Para ver una lista completa de las condicionales, consulta la referencia de condiciones.
Variables
Las condiciones funcionan evaluando 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 la propia configuración del proxy de API. Cada vez que un proxy de API recibe una solicitud de una aplicación, Apigee rellena una larga lista de variables asociadas a elementos como la hora del sistema, la información de la red de la aplicación, los encabezados HTTP de los mensajes, la configuración del proxy de API, las ejecuciones de políticas, etc. De esta forma, se crea un contexto enriquecido que puedes usar para configurar instrucciones condicionales.
Las variables siempre usan una notación con 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.
Supongamos que tienes que crear una instrucción condicional que haga que una política se aplique solo cuando un mensaje de solicitud sea un GET
. Para crear una condición que evalúe el verbo HTTP de una solicitud, crea la instrucción condicional que se muestra a continuación. 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 lo siguiente:
<Condition>request.verb equals "GET"</Condition>
Apigee usa este tipo de instrucción para evaluar las condiciones. El ejemplo anterior se evalúa como verdadero si el verbo HTTP asociado a la solicitud es GET
. Si el verbo HTTP asociado a la solicitud es POST
, la instrucción se evalúa como falsa.
Para habilitar el comportamiento dinámico, puedes adjuntar condiciones a los flujos, los pasos y las reglas de ruta.
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 quieras a un flujo condicional. Un flujo condicional te permite crear reglas de procesamiento muy 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 la solicitud sea GET
, haz lo siguiente:
<Flows> <Flow name="ExecuteForGETs"> <Condition>request.verb="GET"</Condition> </Flow> </Flows>
Para crear un flujo para las solicitudes de GET
y otro para las de POST
, sigue estos pasos:
<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 ejemplo de abajo, puedes aplicar la condición al propio paso de la política. La siguiente condición hace que la política VerifyAPIKey se aplique 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 estos flujos condicionales, podrás adjuntarles políticas, lo que permitirá que un proxy de API aplique un conjunto de políticas a las solicitudes GET
y otro conjunto de políticas a las solicitudes POST
.
Para obtener información de referencia completa, consulta los siguientes recursos:
Ejemplo 1
En el siguiente ejemplo se muestra un flujo condicional llamado Convert-for-devices
,
configurado en el flujo de respuesta de ProxyEndpoint. Añade la condición como elemento a la entidad a la que se aplica. En este ejemplo, la condición es un componente del flujo.
Por lo tanto, el flujo se ejecutará siempre que la instrucción 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>
Por cada solicitud recibida de una aplicación, 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 de ProxyEndpoint anterior, Apigee comprueba 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
, se ejecuta el flujo condicional
y se aplica la política XMLtoJSON llamada ConvertToJSON
. Si no es así, el flujo no se ejecuta y la respuesta XML se devuelve sin modificar (en formato XML) a la aplicación que ha enviado la solicitud.
Ejemplo 2
Vamos a usar un ejemplo concreto en el que necesitas transformar mensajes 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 Weather en JSON:
<XMLToJSON name="ConvertToJSON"> <Options> </Options> <OutputVariable>response</OutputVariable> <Source>response</Source> </XMLToJSON>
La configuración de la política anterior indica al proxy de API que tome el mensaje de respuesta, realice una conversión de XML a JSON con la configuración predeterminada y, a continuación, escriba el resultado en el nuevo mensaje de respuesta. Si vas a convertir un mensaje de solicitud de XML a JSON, solo tienes que asignar el valor request
a ambos.
Como quieres 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 devuelvan a 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 se formatea en JSON.
Sin embargo, tu objetivo es convertir los informes meteorológicos a JSON solo cuando el cliente que hace la solicitud sea un dispositivo móvil. Para habilitar este comportamiento dinámico, debes añadir una instrucción condicional al flujo.
Probar el flujo condicional
En esta solicitud de ejemplo, el encabezado HTTP User-Agent
se define como Mozilla
, lo que hace que la instrucción condicional se evalúe como verdadera y que se ejecute el flujo condicional Convert-for-devices
.
curl -H "User-Agent:Mozilla" http://example.com/weather/forecastrss?w=12797282
o, para mostrar el resultado en un formato más fácil de leer cuando Python esté disponible:
curl -H "User-Agent:Mozilla" http://example.com/weather/forecastrss?w=12797282 | python -mjson.tool
Respuesta de ejemplo:
. . . "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" } ] } . . .
Si se envía una solicitud sin el encabezado User-Agent
o con un valor distinto de Mozilla
, se devolverá una respuesta en formato XML.
$ curl http://example.com/weather/forecastrss?w=12797282
Se devuelve la respuesta XML sin modificar.
Respuesta de ejemplo:
<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 instrucciones condicionales:
- Operador
Matches
: coincidencia de patrones sencilla - Operador JavaRegex: control más preciso de las coincidencias
- Operador
MatchesPath
: coincidencia de fragmentos de ruta
Coincide con
Primero, veamos 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 ofrece dos posibilidades. Coincide con la cadena literalmente o con un comodín *
. Como es de esperar, el comodín coincide con cero o más caracteres. Veamos cómo funciona.
El siguiente XML muestra una condición Step. 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 de Apigee que almacena el sufijo de la ruta de la solicitud. Sin embargo, puedes probar el valor de cualquier variable de flujo que contenga una cadena. 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 ruta es la cadena 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 de proxy hará que se ejecute SomePolicy? Solo hay una posibilidad.
Llamada a la API:
GET http://example.com/matchtest/cat
¿Se ejecuta la política? Sí, porque el sufijo de la ruta del proxy coincide exactamente con /cat
. No se ejecutará si el sufijo es /bat
, /dog
, /
o cualquier otro valor.
Ahora, considera esta instrucción 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
¿Se ejecuta la política? 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
¿Se ejecuta la política? Sí, porque el comodín coincide con cualquier carácter, por lo que "/bat"
es una coincidencia.
Llamada a la API:
GET http://example.com/matchtest/owl
¿Se ejecuta la política? No, ya que el comodín coincide con o
, pero no con las letras wl
.
Ahora, vamos a mover el comodín al final del sufijo:
<Condition>(proxy.pathsuffix Matches "/cat*")</Condition>
Llamada a la API:
GET http://example.com/matchtest/cat
¿Se ejecuta la política? Sí, porque el comodín coincide con cero o más caracteres.
Llamada a la API:
GET http://example.com/matchtest/bat
¿Se ejecuta la política? No, /bat
no es una coincidencia.
Llamada a la API:
GET http://example.com/matchtest/cat123
¿Se ejecuta la política? 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
¿Se ejecuta la política? 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 darte problemas, ya que coincide con todo lo que hay después de los caracteres literales.
Pregunta: ¿El operador Matches
distingue entre mayúsculas y minúsculas?
Sí. Supongamos que tiene una condición como esta:
<Condition>(proxy.pathsuffix Matches "/*At")</Condition>
Llamada a la API:
GET http://example.com/matchtest/cat
¿Se ejecuta la política? No, el comodín coincide con cualquier letra (independientemente de si está en mayúsculas o minúsculas), pero la a
en minúsculas no coincide con A
.
Llamada a la API:
GET http://example.com/matchtest/bAt
¿Se ejecuta la política? Sí, la funda es del mismo color.
Pregunta: ¿Cómo puedo usar caracteres de escape con el operador Matches
?
Usa el carácter de porcentaje %
para aplicar un formato de escape a los caracteres reservados. Por ejemplo:
<Condition>(proxy.pathsuffix Matches "/c%*at")</Condition>
Llamada a la API:
GET http://example.com/matchtest/cat
¿Se ejecuta la política? No, el operador Matches
busca la cadena literal c*at
.
Llamada a la API:
GET http://example.com/matchtest/c*at
Pregunta: ¿Se ejecuta la política?
Sí, esta ruta, aunque es un poco inusual, coincide.
JavaRegex
Como puedes ver, el operador Matches
es ideal para situaciones sencillas. Sin embargo, puedes usar otro operador, JavaRegex o ~~
. Estos dos operadores son iguales, pero se considera que JavaRegex es más legible. Se llama JavaRegex porque permite la coincidencia de patrones de expresiones regulares y Apigee sigue las mismas reglas que las clases del paquete java.util.regex en el lenguaje Java. El operador JavaRegex funciona de forma muy diferente al operador Matches
, por lo que es importante no confundirlos.
Resumen: El operador JavaRegex te permite usar la sintaxis de expresiones regulares en instrucciones condicionales.
El siguiente código muestra una condición de paso. Ejecuta la política SomePolicy si la condición
se evalúa como true
. En este ejemplo, probamos la variable proxy.pathsuffix
, una variable integrada de Apigee que almacena el sufijo de la ruta de la solicitud. Si la ruta base de la solicitud entrante es /animals
y la solicitud es /animals/cat
, el sufijo de ruta es la cadena 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 de proxy hará que se ejecute SomePolicy? Al igual que con el operador Matches
, en este caso solo hay una posibilidad.
Llamada a la API:
GET http://example.com/matchtest/cat
¿Se ejecuta la política? Sí, porque el sufijo de la ruta del proxy coincide exactamente con /cat
. No se ejecutará si el sufijo es /bat
, /dog
o cualquier otro valor.
Ahora, vamos a crear una expresión regular con el cuantificador *
. Este cuantificador coincide con cero o más caracteres anteriores.
<Condition>(proxy.pathsuffix JavaRegex "/c*t")</Condition>
Llamada a la API:
GET http://example.com/matchtest/cat
¿Se ejecuta la política? ¡No! El cuantificador *
coincide con cero o más caracteres anteriores, que son caracteres c
.
Llamada a la API:
GET http://example.com/matchtest/ccccct
¿Se ejecuta la política? Sí, porque el comodín coincide con cero o más caracteres anteriores.
A continuación, usamos el cuantificador ?
, que coincide con el carácter anterior una vez o ninguna.
<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>
Llamada a la API:
GET http://example.com/matchtest/cat
¿Se ejecuta la política? Sí. El cuantificador ?
coincide con cero o una aparición del carácter anterior, que es un a
.
Llamada a la API:
GET http://example.com/matchtest/ct
¿Se ejecuta la política? Sí. El cuantificador ?
coincide con un o
ninguno de los caracteres anteriores. En este caso, no hay ningún carácter a
, por lo que la condición se evalúa como true
.
Llamada a la API:
GET http://example.com/matchtest/caat
¿Se ejecuta la política? No. El cuantificador ?
coincide con uno de los caracteres anteriores, que es un a
.
A continuación, usamos el estilo de expresión regular [abc]
o agrupación. 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
¿Se ejecuta la política? Sí. Aquí usamos expresiones regulares y la expresión [cbr]
coincide con c
, b
o r
. Estas llamadas también son coincidencias:
GET http://example.com/matchtest/bat
GET http://example.com/matchtest/rat
Pero no es una coincidencia:
GET http://example.com/matchtest/mat
Pregunta: ¿El operador JavaRegex distingue entre mayúsculas y minúsculas?
Sí. Supongamos que tiene una condición como esta:
<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>
Llamada a la API:
GET http://example.com/matchtest/cat
¿Se ejecuta la política? Sí, la expresión regular coincide con cero o uno de los caracteres anteriores, que es a
.
Llamada a la API:
GET http://example.com/matchtest/cAt
Pregunta: ¿Se ejecuta la política?
No, porque la letra A
en mayúsculas no coincide con la letra a
en minúsculas.
MatchesPath
El operador MatchesPath
también se puede especificar de esta forma: ~/
. Se parece un poco a los operadores Matches
(~
) y JavaRegex (~~
). Pero MatchesPath
es completamente diferente.
Recuerda que este operador considera una ruta como una serie de partes. Por lo tanto, si la ruta es /animals/cats/wild
, puedes pensar que consta de las partes /animals
, /cats
y /wild
.
El operador MatchesPath
te permite usar dos notaciones de comodín: un asterisco (*) y dos asteriscos (**
). El asterisco simple 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 de Apigee que almacena el sufijo de la ruta de la solicitud. Sin embargo, puedes probar el valor de cualquier variable de flujo que contenga una cadena.
<PreFlow name="PreFlow"> <Request> <Step> <Condition>(proxy.pathsuffix MatchesPath "/animals/*")</Condition> <Name>SomePolicy</Name> </Step> </Request> <Response/> </PreFlow>
Pregunta: ¿Qué sufijo de ruta de proxy hará que se ejecute SomePolicy?
Llamada a la API:
GET http://example.com/matchtest/animals
Pregunta: ¿Se ejecuta la política?
No, porque la condición requiere otro elemento de ruta después de /animals
, tal como se especifica en /*
.
Llamada a la API:
GET http://example.com/matchtest/animals
/
¿Se ejecuta la política? Sí, la ruta tiene otro elemento de ruta (la parte que va después de /animals/
), pero está vacío.
Llamada a la API:
GET http://example.com/matchtest/animals/cats
¿Se ejecuta la política? Sí, porque la ruta tiene claramente un elemento (/cats
)
que va después de /animals
Llamada a la API:
GET http://example.com/matchtest/animals/cats/wild
Pregunta: ¿Se ejecuta la política?
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, vamos a usar el doble asterisco:
<PreFlow name="PreFlow"> <Request> <Step> <Condition>(proxy.pathsuffix MatchesPath "/animals/**")</Condition> <Name>SomePolicy</Name> </Step> </Request> <Response/> </PreFlow>
Pregunta: ¿Qué sufijo de ruta de proxy hará que se ejecute SomePolicy?
Llamada a la API:
GET http://example.com/matchtest/animals
¿Se ejecuta la política? No, porque la condición requiere al menos un elemento de ruta posterior
especificado por /**
.
Llamada a la API:
GET http://example.com/matchtest/animals
/
¿Se ejecuta la política?
Sí, la ruta tiene otro elemento de ruta (la parte que va después de /animals/
), pero está vacío.
Llamada a la API:
GET http://example.com/matchtest/animals/cats
¿Se ejecuta la política?
Sí, porque la ruta tiene al menos un elemento que va después de /animals
.
Llamada a la API:
GET http://example.com/matchtest/animals/cats/wild
¿Se ejecuta la política?
Sí, porque la ruta tiene más de un elemento después de
/animals
Mezclar asteriscos
Puedes usar combinaciones de asterisco simple (*) y doble (**) para acotar aún más 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 una entidad a la que los desarrolladores pueden acceder llamando a tu API. Por ejemplo, si tu servicio proporciona informes y previsiones meteorológicas, tu servicio de backend puede definir dos recursos de API:
http://mygreatweatherforecast.com/reports
http://mygreatweatherforecast.com/forecasts
Cuando creas un proxy de API (como se muestra en el artículo Crea 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 nuevo o equivalente |
---|---|
http://mygreatweatherforecast.com |
http://example.com/mygreatweatherforecast |
En este punto, puede hacer llamadas a la API a su backend con cualquiera de las dos URLs base. Sin embargo, cuando usas la URL del proxy de API, las cosas se ponen interesantes.
Además de las analíticas de APIs que Apigee empieza a recoger cuando usas el proxy de API, los proxies también te permiten definir flujos condicionales que se asignan a los recursos de tu backend. En esencia, si
entra una llamada GET
al recurso /reports
, Apigee debe hacer algo.
En la siguiente imagen se muestra la diferencia de comportamiento entre dos URLs que, en última instancia, acceden al mismo backend. Una es la URL del recurso sin proxy y la otra 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.
Cómo se asignan los proxies de API a recursos de backend específicos
Si asignas una URL de proxy de API a la URL base del servicio de backend (cuando creas el proxy), puedes añadir flujos condicionales a recursos específicos, como los recursos /reports
y /forecasts
que hemos mencionado anteriormente.
Supongamos que quieres que Apigee haga algo cuando se reciban llamadas a los recursos /reports
o /forecasts
. En este punto, no le estás diciendo a Apigee qué debe hacer, solo que debe estar atento a las llamadas a esos recursos. Para ello, usa condiciones. En tu proxy de API de Apigee, puedes crear flujos condicionales para /reports
y /forecasts
. A efectos conceptuales, el siguiente XML de 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 se recibe una solicitud GET
con /reports
y
/forecasts
en la URL, Apigee hará lo que tú (el desarrollador de la API) le digas
a través de las políticas que adjuntes a esos flujos.
Ahora, veamos un ejemplo de cómo indicar a Apigee qué debe hacer cuando se cumpla una condición. En el siguiente XML de 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 opcionales, cada proxy de API también incluye dos flujos predeterminados: un <PreFlow>
que se ejecuta antes de los flujos condicionales y un <PostFlow>
que se ejecuta después de los flujos condicionales. Son útiles para
ejecutar políticas cuando se hace cualquier llamada a un proxy de API. Por ejemplo, si quieres verificar la clave de API de una aplicación con cada llamada, independientemente del recurso de backend al que se acceda, puedes colocar una política de verificación de clave de API en <PreFlow>
. Para obtener más información sobre los flujos, consulta Configurar flujos.
Crear flujos condicionales a recursos de backend
Definir flujos condicionales para recursos de backend en un proxy de API es totalmente opcional. Sin embargo, estos flujos condicionales te permiten aplicar una gestión y una monitorización precisas.
Podrás hacer lo siguiente:
- Aplica la gestión de forma que refleje la semántica de tu modelo de API
- Aplicar políticas y comportamientos basados en secuencias de comandos a rutas de recursos individuales (URIs)
- Recoger métricas detalladas de los servicios de Analytics
Por ejemplo, supongamos que necesitas aplicar diferentes tipos de lógica a los recursos de tu backend /developers
a /apps
.
Para ello, añade dos flujos condicionales a tu proxy de API: /developers
y /apps
.
Nuevo editor de proxies
Para añadir un flujo condicional, sigue estos pasos:
- Selecciona la pestaña Desarrollar en el editor de proxies.
- En el panel de la izquierda, selecciona Endpoints de proxy > default.
- Haz clic en el botón + situado encima del panel Respuesta.
- En el cuadro de diálogo Añadir flujo condicional, introduce las siguientes configuraciones:
- Nombre del flujo:
Developers
- Tipo de condición:
Path
- Ruta:
/developers
La condición se activará (y se ejecutarán las políticas) si se envía una llamada al proxy con
/developers
al final del URI. - Nombre del flujo:
- Ahora, añade un flujo condicional para
/apps
y supongamos que quieres que la condición se active tanto en el URI como en el verboPOST
de una solicitud. La configuración implica definir lo siguiente:- 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 verboPOST
. - Nombre del flujo:
Los flujos añadidos se muestran en el panel Respuesta:
Editor de proxies clásico
En el panel Navegador del panel Desarrollar del editor de proxies de APIs, haz clic en junto a default en Proxy Endpoints.
En la ventana New Conditional Flow (Nuevo flujo condicional), introduce las siguientes configuraciones de claves:
- Nombre del flujo:
Developers
- Tipo de condición:
Path
- Ruta:
/developers
La condición se activará (y se ejecutarán las políticas) si se envía una llamada al proxy
con /developers
al final del URI.
Ahora, añade un flujo condicional para /apps
y supongamos que quieres que la condición se active tanto en el URI como en el verbo POST
de una solicitud. La configuración implica definir lo siguiente:
- 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
.
En el panel Navegador, verás los nuevos flujos de Aplicaciones y Desarrolladores.
Selecciona uno de los flujos para ver la configuración del flujo condicional en la vista de código del editor de proxies 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 la API son simplemente flujos condicionales que evalúan la ruta URI de la solicitud entrante. La variable proxy.pathsuffix
identifica el URI de la solicitud que sigue a BasePath, configurado en la configuración de ProxyEndpoint.
Cada recurso de API que definas se implementa mediante un flujo condicional en el proxy de API. Consulta Configurar flujos.
Una vez que hayas desplegado el proxy de API en el entorno de prueba, la siguiente solicitud:
http://example.com/PROXY_PATH/apps
hará que la condición se evalúe como true
y que se ejecute este flujo, junto con las políticas asociadas.
La siguiente condición de ejemplo usa una expresión regular de Java para reconocer las llamadas realizadas al recurso /apps
con o sin una barra al 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 independientemente de si hay una barra diagonal al final... en la comunidad de Apigee.
Modelado de URIs jerárquicos
En algunos casos, tendrás recursos de API jerárquicos. Por ejemplo, la API de lista de aplicaciones de desarrollador proporciona un método para enumerar todas las aplicaciones que pertenecen a un desarrollador. La ruta del URI es:
/developers/DEVELOPER_EMAIL/apps
Puede que tenga recursos en los que se genere un ID único para cada entidad de una colección, que a veces se anota de la siguiente manera:
/genus/:id/species
Esta ruta se aplica por igual a los dos URIs siguientes:
/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
De esta forma, se resolverán los URIs jerárquicos como recursos de API de forma adecuada.
En algunos casos, sobre todo en las APIs con una jerarquía profunda, puede que solo quieras resolver todo lo que esté por debajo de un fragmento de URI determinado. Para ello, usa un comodín de doble asterisco en la definición del recurso. Por ejemplo, si define el siguiente recurso de API:
/developers/**
Ese recurso de la API resolverá las siguientes rutas de URI:
/developers/DEVELOPER_EMAIL/apps /developers/DEVELOPER_EMAIL/keys /developers/DEVELOPER_EMAIL/apps/APP_ID/keys
Así sería la condición de 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 asociada 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 asociada 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>
Operadores de ejemplo en condiciones
A continuación se muestran 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: ignorar
/
al final de una ruta
Los desarrolladores de Apigee suelen querer gestionar ambos 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, y debes poder gestionarlo en tus instrucciones condicionales. Este caso de uso exacto se ha tratado en el artículo sobre cómo obtener una concordancia independientemente de si hay una barra diagonal al final de la URL.
Si lo prefieres, puedes conseguirlo sin usar expresiones regulares de esta forma:
<PreFlow name="PreFlow"> <Request> <Step> <Condition>(proxy.pathsuffix = "/cat") OR (proxy.pathsuffix = "/cat/")</Condition> <Name>SomePolicy</Name> </Step> </Request> <Response/> </PreFlow>
Es una buena opción. Es clara y legible.
Puedes hacer lo mismo con expresiones regulares, pero de esta forma: Los paréntesis se usan para agrupar la parte de la expresión regular de la instrucción, pero no son obligatorios.
<Condition>(proxy.pathsuffix JavaRegex "/cat(/?)"</Condition>
Llamadas a la API:
GET http://example.com/matchtest/cat
o
GET http://example.com/matchtest/cat
/
¿Se ejecuta la política? Sí. Ten en cuenta que, en una expresión regular, el carácter ?
significa que coincide con cero o con uno de los caracteres anteriores. Por lo tanto, tanto /cat
como /cat/
son coincidencias.
Llamada a la API:
GET http://example.com/matchtest/cat/spotted
¿Se ejecuta la política? No. La expresión regular coincide con cero o solo una aparición del carácter anterior, y no se permite nada más.
Coincidir cadenas 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 útil saber que puedes hacer coincidir patrones con cualquier cadena arbitraria o variable de flujo, tanto si se trata de una variable de flujo integrada, como proxy.pathsuffix
, como si no.
Por ejemplo, si tienes una condición que prueba una cadena arbitraria, como una cadena devuelta en una carga útil de backend o una cadena devuelta de una búsqueda de un servidor de autenticación, puedes usar operadores de coincidencia para probarla. Si usas JavaRegex
, la expresión regular se comparará con toda la cadena del asunto. Si el asunto es abc
y la expresión regular es [a-z]
,
no hay ninguna coincidencia, porque [a-z]
coincide exactamente con un carácter alfabético. La expresión [a-z]+
funciona, al igual que [a-z]*
y [a-z]{3}
.
Veamos un ejemplo concreto. Supongamos que el servidor de autenticación devuelve una lista de roles como
una cadena delimitada por comas: editor, author, guest
.
Para probar la presencia del rol de editor, esta construcción no funcionará, ya que editor
solo forma parte de la cadena completa.
<Condition>returned_roles ~~ "editor"</Condition>
Sin embargo, esta construcción sí funcionará:
<Condition>(returned_roles ~~ ".*\beditor\b.*")</Condition>
Funciona porque tiene en cuenta los saltos de palabra y cualquier otra parte de la cadena con el prefijo y el sufijo .*
.
En este ejemplo, también puedes buscar editor
con el operador Matches
:
<Condition>(returned_roles ~~ "*editor*")</Condition>
Sin embargo, en los casos en los que necesites más precisión, JavaRegex suele ser una mejor opción.
Usar secuencias de escape en expresiones JavaRegex
La sintaxis de Condition requiere que una expresión JavaRegex se incluya entre comillas dobles. Por lo tanto, si tiene una expresión regular que incluye comillas dobles, necesita otra forma de buscar coincidencias con ellas. La respuesta es Unicode. Por ejemplo, supongamos que envías un encabezado que incluye comillas dobles, como el siguiente:
-H 'content-type:multipart/related; type="application/xop+xml"'
Si intentas hacer coincidir ese encabezado en una condición de expresión regular, 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 sustituir las comillas dobles basadas en ASCII por su equivalente 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)"