I am using WSO2 APIM 1.10.0 with my custom handlers which are referenced here.
I have 2 global custom handlers:
HeaderSwapHandler
APIInforHandler
And I want these two custom handlers sequence as follows when the API created.
<handlers>
<handler class="com.wso2.header.handler.HeaderSwapHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.CORSRequestHandler">
<property name="apiImplementationType" value="ENDPOINT"/>
</handler>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.throttling.APIThrottleHandler">
<property name="policyKey" value="gov:/apimgt/applicationdata/tiers.xml"/>
<property name="policyKeyApplication"
value="gov:/apimgt/applicationdata/app-tiers.xml"/>
<property name="id" value="A"/>
<property name="policyKeyResource"
value="gov:/apimgt/applicationdata/res-tiers.xml"/>
</handler>
<handler class="org.wso2.carbon.apimgt.usage.publisher.APIMgtUsageHandler"/>
<handler class="org.wso2.carbon.apimgt.usage.publisher.APIMgtGoogleAnalyticsTrackingHandler">
<property name="configKey" value="gov:/apimgt/statistics/ga-config.xml"/>
</handler>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.ext.APIManagerExtensionHandler"/>
<handler class="com.wso2.header.handler.APIInforHandler"/>
</handlers>
HeaderSwapHandler on the top and APIInforHandler on the bottom of the handlers.
Is there any way to do that?
Edit and Solved
My original velocity_template.xml is like:
<handlers xmlns="http://ws.apache.org/ns/synapse">
<handler class="com.wso2.header.handler.HeaderSwapHandler"/>
<handler class="com.wso2.header.handler.APIInforHandler"/>
#foreach($handler in $handlers)
<handler xmlns="http://ws.apache.org/ns/synapse" class="$handler.className">
#if($handler.hasProperties())
#set ($map = $handler.getProperties() )
#foreach($property in $map.entrySet())
<property name="$!property.key" value="$!property.value"/>
#end
#end
</handler>
#end
</handlers>
#end
#end
#if($apiStatus == 'PROTOTYPED')
#end
## end of apiIsBlocked check
<handlers>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.CORSRequestHandler">
<property name="inline" value="INLINE"/>
</handler>
</handlers>
</api>
Just change to:
<handlers xmlns="http://ws.apache.org/ns/synapse">
<handler class="com.wso2.header.handler.HeaderSwapHandler"/>
#foreach($handler in $handlers)
<handler xmlns="http://ws.apache.org/ns/synapse" class="$handler.className">
#if($handler.hasProperties())
#set ($map = $handler.getProperties() )
#foreach($property in $map.entrySet())
<property name="$!property.key" value="$!property.value"/>
#end
#end
</handler>
#end
<handler class="com.wso2.header.handler.APIInforHandler"/>
</handlers>
#end
#end
#if($apiStatus == 'PROTOTYPED')
#end
## end of apiIsBlocked check
<handlers>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.CORSRequestHandler">
<property name="inline" value="INLINE"/>
</handler>
</handlers>
</api>
That could solve my problem.
In the same page that you are referring, it has Engaging the custom handler section. It shows how you can use velocity_template.xml to engage your new handler to APIs.
Related
I have a REST API on Enterprise Integrator that uses a db lookup mediator to search a microsoft sql server database and redirects based on the whether or not the data exists in the db. I need to make the redirect part of the code configurable/dynamic as it wouldn't make sense to constantly update the url and redeploy every time the url changes.
<api xmlns="http://ws.apache.org/ns/synapse" name="DBLookupAPI" context="/dblookup">
<resource methods="GET" uri-template="/{UserCode}">
<inSequence>
<log level="custom">
<property name="Value" expression="get-property('uri.var.UserCode')"/>
</log>
<dblookup>
<connection>
<pool>
<driver>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver>
<url>jdbc:sqlserver://10.1.1.111\test;databaseName=UserDB</url>
<user>admin</user>
<password>admin</password>
</pool>
</connection>
<statement>
<sql>select UserCode from UserDB.dbo.Users where UserCode =?;</sql>
<parameter expression="get-property('uri.var.UserCode ')" type="CHAR"/>
<result name="foundnr" column="UserCode "/>
</statement>
</dblookup>
<log level="custom">
<property name="Value" expression="get-property('foundnr')"/>
</log>
<filter source="boolean(get-property('foundnr'))" regex="true">
<then>
<log>
<property name="Message" value="Name Exists Lets redirect"/>
</log>
<property name="HTTP_SC" value="302"/>
<property name="Location" value="https://wso2.com/" scope="transport"/>
</then>
<else>
<log>
<property name="Message" value="Name Does Not Exist Lets redirect"/>
</log>
<property name="HTTP_SC" value="302"/>
<property name="Location" value="https://www.youtube.com/" scope="transport"/>
</else>
</filter>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
</api>
You can use the property mediator as below.
<property name="Location" expression="get-property('registry','REGISTRY_PATH')"/>
Below are the possible options for get-property method.
Read from registry
get-property('registry', String registryPath#propertyName)
get-property('registry', String registryPath)
Read from Java System property
get-property('system', String propertyName)
Read from the environment
get-property('env', String propertyName)
Read from a file
get-property('file', String propertyName)
Read from the context
You can use the class mediator or any other mediator and set the redirect url to the context and use the following property mediator to retrieve it from the context.
<property name="Location" expression="$ctx:ERROR_MESSAGE"/>
Please refer the documentation - https://ei.docs.wso2.com/en/latest/micro-integrator/references/mediators/property-reference/accessing-properties-with-xpath/#get-property-function
There are different ways to do this. One way is to read from environment variables. In the following example the Location property is set from the environment variable named REDIRECT_URL.
<property name="Location" expression="get-property('env','REDIRECT_URL')" scope="transport"/>
I'm using WSO2 API Manager Version 2.0.0. Within the API Publisher, I added a POST endpoint to my API using an in path parameter.
POST /person/{id}
Everything works fine. The path parameter id is added to the endpoint.
But this does not work if the path contains a . character somewhere. Adding POST /cool.person/{id} will result in an empty parameter list. Also, it is not possible to add a parameter manually to this endpoint.
Am I doing something wrong or is this a bug?
According to my knowledge and due my findings on this, both POST /person/{id} and POST /cool.person/{id} are correct.
I think the issue is in your endpoint, your end point is not giving permission to you to add another entry via a POST method.
I followed your path and I couldn't reproduce your situation, but I found that need permission from endpoint to put another entry there.
I'll attach my synaps file and snap shot of the response
<?xml version="1.0" encoding="UTF-8"?>
<api xmlns="http://ws.apache.org/ns/synapse"
name="admin--UrlTest"
context="/paternType/1.0"
version="1.0"
version-type="context">
<resource methods="POST" url-mapping="/persons.list" faultSequence="fault">
<inSequence>
<property name="api.ut.backendRequestTime"
expression="get-property('SYSTEM_TIME')"/>
<filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
<then>
<send>
<endpoint name="admin--UrlTest_APIproductionEndpoint_0">
<http uri-template="http://jsonplaceholder.typicode.com/posts?"/>
<property name="ENDPOINT_ADDRESS"
value="http://jsonplaceholder.typicode.com/posts?"/>
</endpoint>
</send>
</then>
<else>
<send>
<endpoint name="admin--UrlTest_APIsandboxEndpoint_0">
<http uri-template="http://jsonplaceholder.typicode.com/posts?"/>
<property name="ENDPOINT_ADDRESS"
value="http://jsonplaceholder.typicode.com/posts?"/>
</endpoint>
</send>
</else>
</filter>
</inSequence>
<outSequence>
<class name="org.wso2.carbon.apimgt.usage.publisher.APIMgtResponseHandler"/>
<send/>
</outSequence>
</resource>
<resource methods="POST" url-mapping="/persons" faultSequence="fault">
<inSequence>
<property name="api.ut.backendRequestTime"
expression="get-property('SYSTEM_TIME')"/>
<filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
<then>
<send>
<endpoint name="admin--UrlTest_APIproductionEndpoint_1">
<http uri-template="http://jsonplaceholder.typicode.com/posts?"/>
<property name="ENDPOINT_ADDRESS"
value="http://jsonplaceholder.typicode.com/posts?"/>
</endpoint>
</send>
</then>
<else>
<send>
<endpoint name="admin--UrlTest_APIsandboxEndpoint_1">
<http uri-template="http://jsonplaceholder.typicode.com/posts?"/>
<property name="ENDPOINT_ADDRESS"
value="http://jsonplaceholder.typicode.com/posts?"/>
</endpoint>
</send>
</else>
</filter>
</inSequence>
<outSequence>
<class name="org.wso2.carbon.apimgt.usage.publisher.APIMgtResponseHandler"/>
<send/>
</outSequence>
</resource>
<resource methods="GET" url-mapping="/personlist" faultSequence="fault">
<inSequence>
<property name="api.ut.backendRequestTime"
expression="get-property('SYSTEM_TIME')"/>
<filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
<then>
<send>
<endpoint name="admin--UrlTest_APIproductionEndpoint_2">
<http uri-template="http://jsonplaceholder.typicode.com/posts?"/>
<property name="ENDPOINT_ADDRESS"
value="http://jsonplaceholder.typicode.com/posts?"/>
</endpoint>
</send>
</then>
<else>
<send>
<endpoint name="admin--UrlTest_APIsandboxEndpoint_2">
<http uri-template="http://jsonplaceholder.typicode.com/posts?"/>
<property name="ENDPOINT_ADDRESS"
value="http://jsonplaceholder.typicode.com/posts?"/>
</endpoint>
</send>
</else>
</filter>
</inSequence>
<outSequence>
<class name="org.wso2.carbon.apimgt.usage.publisher.APIMgtResponseHandler"/>
<send/>
</outSequence>
</resource>
<handlers>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.common.APIMgtLatencyStatsHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.CORSRequestHandler">
<property name="apiImplementationType" value="ENDPOINT"/>
</handler>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.throttling.ThrottleHandler"/>
<handler class="org.wso2.carbon.apimgt.usage.publisher.APIMgtUsageHandler"/>
<handler class="org.wso2.carbon.apimgt.usage.publisher.APIMgtGoogleAnalyticsTrackingHandler">
<property name="configKey" value="gov:/apimgt/statistics/ga-config.xml"/>
</handler>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.ext.APIManagerExtensionHandler"/>
</handlers>
</api>
Jeewana.
I need to append a fixed Authorization header to an API endpoint. This is an application specific token for my endpoint system so I do not need API subscribers to enter this information nor want them in the know.
An almost similar question was raised before but hasn't been answered.
The documentation here doesn't provide specific details and is a bit obscure so I am lost on how to achieve this. Has anybody done this?
Appreciate any help, cheers!
Do you want to set this as a custom HTTP header and send it to the backend? If yes, then you can use a property mediator to set this as a transport scope property just before the send mediator inside inSequence of your API, as shown below. Have a look at the property Fixed-Authorization set just before the send mediator.
<?xml version="1.0" encoding="UTF-8"?>
<api xmlns="http://ws.apache.org/ns/synapse"
name="admin--Hello"
context="/hello"
version="1.0.0"
version-type="url">
<resource methods="POST GET OPTIONS DELETE PUT"
url-mapping="/*"
faultSequence="fault">
<inSequence>
<filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
<then>
<property name="Fixed-Authorization" value="yourAppToken" scope="transport"/>
<send>
<endpoint name="admin--Hello_APIproductionEndpoint_0">
<http uri-template="http://echo.jsontest.com/key/value/one/two"/>
</endpoint>
</send>
</then>
<else>
<sequence key="_sandbox_key_error_"/>
</else>
</filter>
</inSequence>
<outSequence>
<send/>
</outSequence>
</resource>
<handlers>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.throttling.APIThrottleHandler">
<property name="id" value="A"/>
<property name="policyKey" value="gov:/apimgt/applicationdata/tiers.xml"/>
</handler>
<handler class="org.wso2.carbon.apimgt.usage.publisher.APIMgtUsageHandler"/>
<handler class="org.wso2.carbon.apimgt.usage.publisher.APIMgtGoogleAnalyticsTrackingHandler">
<property name="configKey" value="gov:/apimgt/statistics/ga-config.xml"/>
</handler>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.ext.APIManagerExtensionHandler"/>
</handlers>
</api>
If you access the API, this property will be sent as a HTTP header to your backend endpoint. You can refer this post for more detailed explanation.
If you just want to pass this application token to the backend (but not as HTTP header), then you can pass it to the backend using JWT. Refer this document for more details.
I need to transform my csv file to XML with elements with prefixes "api".
I have WSO2 ESB configuration like this:
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="c"
transports="https http local vfs"
startOnLoad="true"
trace="enable">
<description/>
<target>
<inSequence>
<smooks config-key="sm">
<input type="text"/>
<output type="xml"/>
</smooks>
<log level="full"/>
</inSequence>
<outSequence/>
<faultSequence>
<log level="full"/>
</faultSequence>
</target>
<parameter name="transport.vfs.ActionAfterProcess">MOVE</parameter>
<parameter name="transport.PollInterval">5</parameter>
<parameter name="transport.vfs.MoveAfterProcess">file://D:\test\out</parameter>
<parameter name="transport.vfs.FileURI">file://D:\test</parameter>
<parameter name="transport.vfs.MoveAfterFailure">file://D:\test\fail</parameter>
<parameter name="transport.vfs.FileNamePattern">.*.csv</parameter>
<parameter name="transport.vfs.ContentType">text/plain</parameter>
<parameter name="transport.vfs.ActionAfterFailure">MOVE</parameter>
</proxy>
<localEntry key="sm">
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
xmlns:core="http://www.milyn.org/xsd/smooks/smooks-core-1.3.xsd"
xmlns:csv="http://www.milyn.org/xsd/smooks/csv-1.2.xsd">
<resource-config selector="org.xml.sax.driver">
<resource>org.milyn.csv.CSVReader</resource>
<param name="fields">code,name</param>
<param name="rootElementName">api:root</param>
<param name="recordElementName">api:rec</param>
</resource-config>
</smooks-resource-list>
</localEntry>
<sequence name="fault">
<log level="full">
<property name="MESSAGE" value="Executing default "fault" sequence"/>
<property name="ERROR_CODE" expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE" expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<log/>
<drop/>
</sequence>
</definitions>
Without prefix api it works, else - not.
Where I just did not added namespaces - it's did not help me.
Anybody can help? Thanks.
I have a simple use case of mapping path param from the API consumer to the backend API endpoint. I have done a lot of research but have not found out the specific answer on how to do that. As per my understanding, thr mapping of the path parameter can't be done without the use of uri-template. Now the problem is that the API Manager does not support uri-template from the API Publisher user interface and you have to use url-mapping instead. One blog from WSO2 developer says that you can then go to the individual synapse config and change that to uri-template manually. But what is happening in pratice is that the updates made to the synapde config somehow triggers the database update that would happen from the publisher UI otherwise and the end result is that it does not work. Can someone please provide the way forward on how the path param can be mapped? FYI - the query parameter mapping is working for me since that does not need uri-template and can be implemented using url-mapping itself.
APIM 1.8 support both uri-template and url-mapping.You can define your url-template(or if you want uri-mapping) under resource section. please see the synapse config where i have added url-template and a url-mapping
in publisher I added /json as url pattern for url-mapping and /json/{id} for uri-template
<?xml version="1.0" encoding="UTF-8"?>
<api xmlns="http://ws.apache.org/ns/synapse"
name="admin--mytst"
context="/mytest"
version="1"
version-type="url">
<resource methods="GET" url-mapping="/json" faultSequence="fault">
<inSequence>
<filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
<then>
<send>
<endpoint name="admin--mytst_APIproductionEndpoint_0">
<http uri-template="http://localhost.com"/>
</endpoint>
</send>
</then>
<else>
<sequence key="_sandbox_key_error_"/>
</else>
</filter>
</inSequence>
<outSequence>
<send/>
</outSequence>
</resource>
<resource methods="GET" uri-template="/json/{id}" faultSequence="fault">
<inSequence>
<filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
<then>
<send>
<endpoint name="admin--mytst_APIproductionEndpoint_1">
<http uri-template="http://localhost.com"/>
</endpoint>
</send>
</then>
<else>
<sequence key="_sandbox_key_error_"/>
</else>
</filter>
</inSequence>
<outSequence>
<send/>
</outSequence>
</resource>
<handlers>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.throttling.APIThrottleHandler">
<property name="id" value="A"/>
<property name="policyKey" value="gov:/apimgt/applicationdata/tiers.xml"/>
</handler>
<handler class="org.wso2.carbon.apimgt.usage.publisher.APIMgtUsageHandler"/>
<handler class="org.wso2.carbon.apimgt.usage.publisher.APIMgtGoogleAnalyticsTrackingHandler">
<property name="configKey" value="gov:/apimgt/statistics/ga-config.xml"/>
</handler>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.ext.APIManagerExtensionHandler"/>
</handlers>
</api>`enter code here`