how to force text/plain in WSO2 call to an endpoint - wso2

I have an enrich mediator in a sequence which has a value in a plain text. I have verified the value with log and ensured it is a text. But when I do the call after the enrich (see below) the API received the payload as a JSON with key always as "test": and then the plaintext value.
The API below expects any values, it just saves the body to a file. When I try to set a property before the call to state message type=text/plain it just hangs, does not do the call?
QUESTION: Does WSO2 mediator (wso2 framework) by nature expects the body to be either be JSON or XML? NOT Text/Plain allowed. If this is true, then I have to change my API to handle this issue I Think.
If someone can answer that question, I think I will know what to do. Because when I call the same API using a java class mediator with same options it works fine.
<call>
<endpoint>
<http method="POST" uri-template="http://xxxxxxx.38:8280/writefile"/>
</endpoint>
</call>

Thanks for the update. I had tried that before, when I had that the process was hanging and would not call the api. Here is what we did for it to work:
<payloadFactory media-type="xml">
<format>
<text xmlns="http://ws.apache.org/commons/ns/payload">$1</text>
</format>
<args>
<arg evaluator="xml" expression="get-property('fileContent')"/>
</args>
</payloadFactory>
<property name="messageType" scope="axis2" type="STRING" value="text/plain"/>
Thanks for the update folks. First time asking a questions and good to see getting response ASAP. Will try to contribute my learning and try to help .

Add this before the call mediator.
<property name="messageType" value="text/plain" scope="axis2"/>

Related

How to publish WSO2 API on WSO2?

I have a special requirement.
I want to access WSO2 backen API.
So,I want to publish it on WSO2.
So that,my service can access WSO2'API.
Can someone tell me how to do it?
WSO2 API Manager exposes a REST API to for operations like publish and subscribe. You can see the list of all the services here: https://docs.wso2.com/display/AM200/Published+APIs.
It also offers Swagger definition files for those same APIs: https://raw.githubusercontent.com/wso2/carbon-apimgt/v6.0.4/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher/src/main/resources/publisher-api.yaml.
I haven't tried it, but given the fact that all you need to publish a managed API in WSO2 is a Swagger file and an existing endpoint, there is nothing preventing you to create an API for WSO2 APIM inside itself.
Theoretically, this should be fine.
WSO2 API manger plays the middleware role for its own APIs just as for any other third party API.
Let's say that you want to publish any of the Admin APIs of the api manager through the api manager itself. You just need to add endpoint information just as you would do for any other api.
Then, once a user wants to access the api, they have to first get a access token by calling the token endpoint, then use that token to execute the published api.
Access you API-Manager on: http://localhost:9443/publisher
Click on your api
Click on tab "Lifecycle"
Click on "Publish"
WS02 API means are you referring to Wso2 API manager?
Because you can also implement API's using Wso2 ESB.
You can have more control over the code of API using Wso2 ESB but you cannot have throttling and other control using ESB you have to use APIM.
You shoould have an endpoint to connect your API.
Then follow the below steps
Login in your API Manager (Publisher) Instance.
+ Add new API
If you have an endpoint: Click on Design a new Rest API
Fill the values like name, context, version and description.
Add a new API Specification. (i.e: GET /test)
Click on Next:Implement
Select Managed API
Endpoint Type: HTTP/REST Endpoint
Endpoint: Fill your endpoint's url without context.
Click on Next: Manage
Fill values like type of subscription.
If you have a public API, don't forget change the second column of your API specification resources. Change the value for: None
Click on Save & Publish
Go to WSO2 Store and check
While going through the answers and the replies that you have provided, I believe you know how to publish an API with a WSO2 API as an endpoint. However, your concern is how to handle the authorization since the backend itself needs a valid OAuth token to be invoked? Please correct me if my understanding is wrong.
If that is the case, I believe you can simply achieve it with a help of a custom mediation. The below sample mediation is to invoke the token endpoint and generate a token. Once the token is generated you can simply add that to the request header.
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="simple-token-gen" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<property description="access_token" expression="get-property('registry', 'local:/api-backend-credentials/pizzaOrderingAPI/access_Token')" name="access_token" scope="default" type="STRING"/>
<property description="generated_time" expression="get-property('registry','local:/api-backend-credentials/pizzaOrderingAPI/generated_Time')" name="generated-time" scope="default" type="LONG"/>
<property description="client_credentials" name="app-client-auth" scope="default" type="STRING" value="{base64encoded(clientKey:clientSecret)}"/>
<property expression="json-eval($)" name="message-body" scope="default" type="STRING"/>
<property expression="get-property('axis2','REST_URL_POSTFIX')" name="resource" scope="default" type="STRING"/>
<filter description="" xpath="get-property('SYSTEM_TIME') - get-property('generated-time') > 3600000 or get-property('access_token') = ''">
<then>
<payloadFactory media-type="xml">
<format>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<root xmlns="">
<grant_type>client_credentials</grant_type>
</root>
</soapenv:Body>
</soapenv:Envelope>
</format>
<args/>
</payloadFactory>
<header expression="fn:concat('Basic ', get-property('app-client-auth'))" name="Authorization" scope="transport"/>
<header name="Content-Type" scope="transport" value="application/x-www-form-urlencoded"/>
<property description="messageType" name="messageType" scope="axis2" type="STRING" value="application/x-www-form-urlencoded"/>
<property description="REST_URL_POSTFIx" name="REST_URL_POSTFIX" scope="axis2" type="STRING" value=""/>
<call blocking="true">
<endpoint name="token">
<http method="post" uri-template="{token-endpoint-url}"/>
</endpoint>
</call>
<property expression="get-property('resource')" name="REST_URL_POSTFIX" scope="axis2" type="STRING"/>
<property description="generated Time Setter" expression="get-property('SYSTEM_TIME')" name="local:/api-backend-credentials/pizzaOrderingAPI/generated_Time" scope="registry" type="LONG"/>
<property description="generated_token" expression="json-eval($.access_token)" name="generated-access-token" scope="default" type="STRING"/>
<property description="new Token setter" expression="get-property('generated-access-token')" name="local:/api-backend-credentials/pizzaOrderingAPI/access_Token" scope="registry" type="STRING"/>
<header expression="fn:concat('Bearer ', get-property('generated-access-token'))" name="Authorization" scope="transport"/>
<payloadFactory media-type="json">
<format>
$1
</format>
<args>
<arg evaluator="xml" expression="get-property('message-body')"/>
</args>
</payloadFactory>
</then>
<else>
<header expression="fn:concat('Bearer ', get-property('access_token'))" name="Authorization" scope="transport"/>
</else>
</filter>
</sequence>
Replace the placeholders with corresponding values.
{base64encoded(clientKey:clientSecret)} - The client key and client
secret, separated by a colon and base64 encoded. {token-endpoint-url}
The token endpoint URL of the backend authorization server.
I believe this helps you with your concern.
If I understood correctly, It has no sense to publish WSO2 AM APIs in the API Manager. First reason is that WSO2 AM APIs are accesed by Basic Auth, that it is not implemented by default in WSO2 AM. The default security for APIs en WSO2 is OAuth2, so you would have to do a extension for that. You may check here: https://docs.wso2.com/display/AM260/apidocs/publisher/#guide
Also, these internal APIs for WSO2 AM are meant to be accesed by an admin or so, so it has no sense to expose these as an API to be consumed for other suscriptors.
Anyway, if you implemented an authenticator to run with Basic Auth, you may expose this APIs in API Manager, or expose these APIs disabling default OAuth2 security.
BR

How to retrieve HTTP REST METHOD of current service at Run time in WSO2 AM Sequence?

How to retrieve HTTP REST METHOD(GET,PUT,POST,DELETE,OPTIONS) in WSO2 Api Manager's Sequence at runtime? I tried to $ctx:REST_METHOD which returns 'null' value.
<sequence name="ec_rest_dynamic_ep" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<property expression="$ctx:REST_METHOD" name="restmethod"
scope="default" type="STRING"/>
<log>
<property expression="get-property('restmethod')" name="*******************REST_METHOD***********"/>
</log>
</sequence>
Basically, HTTP REST METHOD value of current service & URL context of that service needed to identify the service in order redirect the service to its endpoint dynamically at runtime.
Try the following property.
<property name="Http_Method" expression="get-property('axis2', 'HTTP_METHOD')"/>
You can find more useful properties in [1].
#Pubci's answer is correct. Here is another way.
<property name="Method" scope="transport" expression="$ctx:api.ut.HTTP_METHOD"/>
Some other properties can be found here.

WSO2 ESB- PayloadFactory for different operations

I have a backend service with multiple operations. (for example,echoInt and echoString). I want to replace input value for both of them with predefined variables(in the inSequence) with PayloadFactory mediator.
How can i define payloadfactory for different operations?
when i define two payloadfactory mediator for each of them, only the last mediator works for it's operation. when i call other opertaion, this error occures:
wso2 namespace mismatch
operation1:
<p:echoString xmlns:p="http://echo.services.core.carbon.wso2.org">
<in>$1</in>
</p:echoString>
operation2:
<p:echoInt xmlns:p="http://echo.services.core.carbon.wso2.org">
<in>$1</in>
</p:echoInt>
My inSequense:
<inSequence>
<payloadFactory media-type="xml">
<format>
<p:echoString xmlns:p="http://echo.services.core.carbon.wso2.org">
<in xmlns="">teststr</in>
</p:echoString>
</format>
<args/>
</payloadFactory>
<payloadFactory media-type="xml">
<format>
<p:echoInt xmlns:p="http://echo.services.core.carbon.wso2.org">
<in xmlns="">1111</in>
</p:echoInt>
</format>
<args/>
</payloadFactory>
</inSequence>
with above inSequense, output result for both operations is '1111':
<ns:echoStringResponse xmlns:ns="http://echo.services.core.carbon.wso2.org">
<return>1111</return>
</ns:echoStringResponse>
thanks in advance
The second Payload factory replaces the first.
If you want to use each of them in a different case, you should define them in a Switch mediator.
You can use a property to get the input that defines which case you should use, then use regex to match the property value. Or you could skip the property and enter the expression in the Switch source.
At the end it would look similar to:
<inSequence>
<property expression="/default/expression" name="input_string" scope="default" type="STRING"/>
<switch source="get-property('input_string')">
<case regex="[\w\s]+">
<payloadFactory media-type="xml">
<format>
<p:echoString xmlns:p="http://echo.services.core.carbon.wso2.org">
<in xmlns="">teststr</in>
</p:echoString>
</format>
<args/>
</payloadFactory>
</case>
<default>
<payloadFactory media-type="xml">
<format>
<p:echoInt xmlns:p="http://echo.services.core.carbon.wso2.org">
<in xmlns="">1111</in>
</p:echoInt>
</format>
<args/>
</payloadFactory>
</default>
</switch>
<respond/>
</inSequence>
If you want call two operations in same time, you should use the clone or iterate Mediator, and use the aggregate Mediator in the outsequence.
The reason you use the two payloadFactory, only last one works, is that one request only have one message context, this mean, you only can send one soap message to back end in same time. This mean the last payloadFactory will override the first one.
Clone or iterate Mediator will clone or split one message context to multiple message context, then you can send multiple soap message to back end services. Because of you got multiple message context, then you should use the aggregate Mediator to aggregate these multiple responses into one message context after back end services return the result.

WSO2 API manager prototype API HTTP response status

I am using the inline javascript prototype feature in the WSO2 API manager and I'm trying to set different HTTP response statuses. Is this possible? If so how is it done?
So far I have tried setting the HTTP_SC property but this doesn't seem to have any effect.
mc.setProperty('HTTP_SC', "404");
I had the same requirement and after much exploring under the hood was able to find a workable solution.
The reason why setting the property:
mc.setProperty('HTTP_SC', "404");
didn't work is that the property needs to be set in the axis2 scope (as Abimaran said). mc.setProperty doesn't set it on that scope. Moreover, the MessageContext object doesn't provide a way to set the scope.
The 'Deploy as Prototype' action actually creates the API definition file by merging the specified in-line script into the a velocity template and storing the resulting API definition into a file.
Template: ./repository/resources/api_templates/prototype_template.xml
Output location: repository/deployment/server/synapse-configs/default/api/
The output file will have a name in the format:
provider--API Name-vVERSION.xml
where provider appears to be the username of the API creator.
What I did was add a filter to the template:
<filter source="boolean(get-property('HTTP_SC'))" regex="false">
<then>
<property name="HTTP_SC" value="200" scope="axis2"/>
</then>
<else>
<property name="HTTP_SC" expression="get-property('HTTP_SC')" scope="axis2"/>
</else>
</filter>
I added it immediately after a similar block (for handling CONTENT_TYPE) at the start of the inSequence element.
You need to add following properties before <send/> mediator
<header name="To" action="remove"/>
<property name="RESPONSE" value="true"/>
<property name="HTTP_SC" value="403" scope="axis2"/>

Rebuilding the initial message using the payload factory mediator

I'm involved in a proxy service development using WSO2.
In my sequence I've saved the initial current message in a property using the following:
<property name="InitialMessage" expression="$body" scope="default" type="STRING"/>
and now I need to rebuild the initial message using the payload factory mediator. Am I right? What are some considerable alternatives?
Could someone show me the right syntax in this case?
yes your method is correct, But I would suggest you to save only the required properties from your incoming message and use them in building the new message. Sample Syntax is given below
<payloadfactory>
<format>
<m:checkpriceresponse xmlns:m="http://services.samples/xsd">
<m:code>$1</m:code>
<m:price>$2</m:price>
</m:checkpriceresponse>
</format>
<args>
<arg expression="//m0:symbol" xmlns:m0="http://services.samples/xsd">
<arg expression="//m0:last" xmlns:m0="http://services.samples/xsd">
</arg></arg></args>
</payloadfactory>
I've solved my problem using the enrich mediator: Here you are how ...
I've saved my initial message in a property InitialMessage in this manner ...
<property name="InitialMessage" expression="$body" scope="default" type="STRING"/>
and after I've used the enrich mediator in this manner
<enrich>
<source type="property" clone="true" property="InitialMessage"/>
<target type="body"/>
</enrich>
It's working ...
I hope this could be useful ...