WSO2 MI How to create an Insert or Update PUT resource? - wso2

I want to create a PUT resource in WSO2 Micro Integrator, so I can either insert or update event records, but it's not even accepting my http request. Could you help me configure this correctly?
What I was expecting was that when I'd call something like this, it would insert in batch into the database.
curl --location --request PUT 'http://wso2-mi.mkwtf.com/services/APIDataService/eventRecord?calendar_date=2022-12-01' \
--header 'Content-Type: application/xml' \
--data-raw '
<event_record_list>
<event_record>
<event_type>1000124</event_type>
<event_count>217140</event_count>
</event_record>
<event_record>
<event_type>1000127</event_type>
<event_count>1567</event_count>
<event_record>
</event_record>
<event_type>1000129</event_type>
<event_count>31</event_count>
</event_record>
</event_record_list>'
But in reality it responds with this:
<axis2ns52:DataServiceFault xmlns:axis2ns52="http://ws.wso2.org/dataservice">
<axis2ns52:current_params>{event_type=1000124, event_count=217140}</axis2ns52:current_params>
<axis2ns52:source_data_service>
<axis2ns52:data_service_name>APIDataService</axis2ns52:data_service_name>
<axis2ns52:description></axis2ns52:description>
<axis2ns52:location>/home/wso2/qa/wso2mi/tmp/carbonapps/-1234/1671624403635APICompositeExporter_1.0.0.car/APIDataService_1.0.0/APIDataService-1.0.0.dbs</axis2ns52:location>
<axis2ns52:default_namespace>http://ws.wso2.org/dataservice</axis2ns52:default_namespace>
</axis2ns52:source_data_service>
<axis2ns52:ds_code>INCOMPATIBLE_PARAMETERS_ERROR</axis2ns52:ds_code>
<axis2ns52:current_request_name>_puteventrecord</axis2ns52:current_request_name>
</axis2ns52:DataServiceFault>
However, when I make this request, I'm able to make the request, and it returns me with 202, but I'm only able to insert or update one row at a time.
curl --location --request PUT 'http://wso2-mi.mkwtf.com/services/APIDataService/eventRecord?calendar_date=2022-12-01&event_type=1000124&event_count=217140' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'calendar_date=2022-12-01' \
--data-urlencode 'event_type=1000124' \
--data-urlencode 'event_count=217140'
Here is the Data Service definition:
<data name="APIDataService" serviceNamespace="" serviceGroup="" transports="http https local">
<description />
<config id="postgresDataService">
<property name="carbon_datasource_name">APIPostgres</property>
</config>
<query id="eventRecord" useConfig="postgresDataService">
<sql>
INSERT INTO event_record(calendar_date, event_type, event_count)
VALUES (:calendar_date, :event_type, :event_count)
ON CONFLICT (calendar_date, event_type)
DO UPDATE SET event_count = EXCLUDED.event_count
</sql>
<param name="calendar_date" sqlType="date" />
<param name="event_type" sqlType="integer" />
<param name="event_count" sqlType="integer" />
<properties>
<property name="forceJDBCBatchRequests">true</property>
</properties>
</query>
<resource method="PUT" path="eventRecord">
<call-query href="eventRecord">
<with-param name="calendar_date" query-param="calendar_date" />
<with-param name="event_type" query-param="event_type" />
<with-param name="event_count" query-param="event_count" />
</call-query>
</resource>
</data>

Due to a limitation of MI[1], you cannot use both the request body and URL params to call a dataservice. When the content type is set in the request it tries to dispatch to the data service operation based on the request body and ignores the URL params. As a result, you will observe the INCOMPATIBLE_PARAMETERS_ERROR error. Therefore you will need to pass all the required parameters of the eventRecord operation in your request body. Can you try to send a request as follows,
curl --location --request PUT 'http://wso2-mi.mkwtf.com/services/APIDataService/eventRecord' \
--header 'Content-Type: application/xml' \
--data-raw '
<event_record_list>
<event_record>
<calendar_date>2022-12-01</calendar_date>
<event_type>1000124</event_type>
<event_count>217140</event_count>
</event_record>
<event_record>
<calendar_date>2022-12-01</calendar_date>
<event_type>1000127</event_type>
<event_count>1567</event_count>
<event_record>
</event_record>
<calendar_date>2022-12-01</calendar_date>
<event_type>1000129</event_type>
<event_count>31</event_count>
</event_record>
</event_record_list>'
[1] - https://github.com/wso2/product-ei/issues/2811

Related

Create parameters in API Header in WSO2

I have created a API in WSO2 studio integrator like below:
curl --location --request POST 'http://localhost:8290/internal/send-messages'
--header 'accept: text/plain'
--header 'Content-Type: application/json'
--data-raw '{
"bankName": "heere",
"uniqueIdentifier": "445334564"
}'
To pass the requests (which received from this API) toward the endpoint, I need to add two following parameters into API Header
--header 'MasterName: TOMSON'
--header 'clientName: TOM' \
TOMSON value is unique(static) and would NOT change for any user.
However TOM would be change based on application username given from API Manager (there is OATH2 authentication).
How can I add a static header (Like MasterName) to a API while sending toward the endpoint
How can I understand the username of application ??
You can add a static header using the header mediator[1].
<header name="MasterName" value="TOMSON" scope="transport"/>
To get the application information from the API Manager, you can enable backend JWT[2]. This will be a JWT generated with much more information regarding the request. By decoding this[3] JWT at the backend, you can get the application information with the claim http://wso2.org/claims/applicationname.
[1] - https://ei.docs.wso2.com/en/latest/micro-integrator/references/mediators/header-Mediator/
[2] - https://apim.docs.wso2.com/en/latest/deploy-and-publish/deploy-on-gateway/api-gateway/passing-enduser-attributes-to-the-backend-via-api-gateway/
[3] - WSO2 Decode JWT
You can use header mediator to add headers
For example
<header name="miCustomHeader" value="ThisIsTheWay" scope="transport"/>
<send>
<endpoint>
<address uri="https://someRandomURL"/>
</endpoint>
</send>
It will send miCustomHeader along its value to the endpoint

WSO2 EI 6.6 Content-Type is null for GET requests

I'm having an API endpoint defined in WSO2 EI Integration studio. When I send this endpoint a GET request, the $axis2:ContentType header of the request is getting null as soon as it comes inside the EI (Beginning of inSequence) . Is there a way to preserve this header and send it out of the EI. Any idea how to do this ?
NOTE: This is not happening for POST requests.
API endpoint
<?xml version="1.0" encoding="UTF-8"?>
<api context="/eirouter_test" name="eirouter_test" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST GET">
<inSequence>
<log level="custom">
<property expression="$axis2:ContentType" name="original-content-type" />
</log>
<respond description="Send result to the client"/>
</inSequence>
<outSequence />
<faultSequence />
</resource>
</api>
Request CURL
curl --location --request GET 'http://localhost:8290/eirouter_test/eb805bbe-6c3e-414d-a380-857b6f89607c' \
--header 'Content-Type: application/json'
EI Logs
[2021-06-01 10:54:41,457] INFO {LogMediator} - {api:eirouter_test} original-content-type = null
In short answer, the Content-Type HTTP header should be set only for PUT and POST requests. There was very similar question: Do I need a content-type header for HTTP GET requests?
with very good explanations.
So that is not WSO2 problem, but that is how works HTTP with Content-Type header.

WSO2 Data Service Not Binding Inputs

I've trying to create a simple data service that inserts an entry in our database with the following definition:
<data name="RESTLoggerDataService" serviceNamespace="" transports="http https">
<config id="default">
<property name="driverClassName">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="url">jdbc:sqlserver://SERVER:1433;databaseName=DB</property>
<property name="username">user</property>
<property name="password">pass</property>
</config>
<query id="CreateLog" useConfig="default">
<sql>INSERT INTO Log (Date, Username, ServiceID) VALUES (?,?,?)</sql>
<param name="Date" paramType="SCALAR" sqlType="STRING" type="IN" ordinal="1"/>
<param name="Username" paramType="SCALAR" sqlType="STRING" type="IN" ordinal="2"/>
<param name="ServiceID" paramType="SCALAR" sqlType="STRING" type="IN" ordinal="3"/>
</query>
<resource method="POST" path="Log">
<call-query href="CreateLog">
<with-param name="Date" query-param="Date"/>
<with-param name="Username" query-param="Username"/>
<with-param name="ServiceID" query-param="ServiceID"/>
</call-query>
</resource>
</data>
It seems this is not quite valid as none of the parameters I'm passing in via a CURL call are binding. I've tried:
curl -X POST -H 'Accept: application/xml' -H 'Content-Type: application/xml' --data "#test.xml" http://localhost:90/services/RESTLoggerDataService/Log
with the following XML:
<_postlog>
<Date>2020-09-15 09:06:00.000</Date>
<Username>KIRBJJ</Username>
<ServiceID>WA233</ServiceID>
</_postlog>
but get the following back:
curl: (52) Empty reply from server
curl: (52) Empty reply from server
<axis2ns19:DataServiceFault xmlns:axis2ns19="http://ws.wso2.org/dataservice"><axis2ns19:current_params>{Username=null, Date=null, ServiceID=null}</axis2ns19:current_params><axis2ns19:source_data_service><axis2ns19:data_service_name>RESTLoggerDataService</axis2ns19:data_service_name><axis2ns19:description>Exposing the data service as a REST service.</axis2ns19:description><axis2ns19:location>C:\PROGRA~1\WSO2\ENTERP~1\7154FB~1.0\MICRO-~1\bin\..\tmp\carbonapps\-1234\1600259919991RestLoggerCompositeExporter_1.0.0.car\RESTDataService_1.0.0\RESTDataService-1.0.0.dbs</axis2ns19:location><axis2ns19:default_namespace>http://ws.wso2.org/dataservice</axis2ns19:default_namespace></axis2ns19:source_data_service><axis2ns19:ds_code>DATABASE_ERROR</axis2ns19:ds_code><axis2ns19:nested_exception>com.microsoft.sqlserver.jdbc.SQLServerException: Cannot insert the value NULL into column 'Date', table 'LOGS.dbo.LogEntry'; column does not allow nulls. INSERT fails.</axis2ns19:nested_exception><axis2ns19:current_request_name>_postlog</axis2ns19:current_request_name></axis2ns19:DataServiceFault>
<axis2ns8:DataServiceFault xmlns:axis2ns8="http://ws.wso2.org/dataservice">
<axis2ns8:current_params>{}</axis2ns8:current_params>
<axis2ns8:source_data_service>
<axis2ns8:data_service_name>RESTLoggerDataService</axis2ns8:data_service_name>
<axis2ns8:description>Exposing the data service as a REST service.</axis2ns8:description>
<axis2ns8:location>C:\PROGRA~1\WSO2\ENTERP~1\7154FB~1.0\MICRO-~1\bin\..\tmp\carbonapps\-1234\1600263784524RestLoggerCompositeExporter_1.0.0.car\RESTDataService_1.0.0\RESTDataService-1.0.0.dbs</axis2ns8:location>
<axis2ns8:default_namespace>http://ws.wso2.org/dataservice/LoggingAPI</axis2ns8:default_namespace>
</axis2ns8:source_data_service>
<axis2ns8:ds_code>INCOMPATIBLE_PARAMETERS_ERROR</axis2ns8:ds_code>
<axis2ns8:current_request_name>_postlog</axis2ns8:current_request_name>
</axis2ns8:DataServiceFault>
It appears the input parameters are not binding correctly. Can anybody see what I'm doing wrong?
I have created a similar data service with MySQL and did not face any issues. Could you please try the following and see if it makes any changes. Change the payload by adding namespaces as follows and try the same mediation.
<p:_postlog xmlns:p="http://ws.wso2.org/dataservice">
<xs:Date xmlns:xs="http://ws.wso2.org/dataservice">2020-09-15 09:06:00.000</xs:Date>
<xs:Username xmlns:xs="http://ws.wso2.org/dataservice">KIRBJJ</xs:Username>
<xs:ServiceID xmlns:xs="http://ws.wso2.org/dataservice">WA233</xs:ServiceID>
</p:_postlog>
If this does not work please enable wire logs and confirm that the correct payload is passed to the data service.

404 Not Found in Wso2apimanager

I created an api in wso2apimanager 1.7 and subscribed the created api through creating an application. But when i call the api using a REST client (postman) i'm getting 404 Not Found error.
cURL request
curl -X GET -H "Cache-Control: no-cache" -H "Authorization: Bearer f3afa04c46c95461ff2df4d037e9b2f" -H "Postman-Token: 8cb664dd-76ec-5ee1-40ee-ff27a1ce1942" "http://localhost:8280/test/path/V1/"
Response is
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
below is my api definition xml
<?xml version="1.0" encoding="UTF-8"?>
<api xmlns="http://ws.apache.org/ns/synapse"
name="admin--TestingAPI"
context="/test/path"
version="V1"
version-type="url">
<resource methods="POST GET OPTIONS DELETE PUT"
url-mapping="/*"
faultSequence="fault">
<inSequence>
<send>
<endpoint name="admin--TestingAPI_APIproductionEndpoint_0">
<http uri-template="http://httpbin.org/ip"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<send/>
</outSequence>
</resource>
<handlers>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.CORSRequestHandler"/>
</handlers>
</api>
I think the problem is with your backend service. It gives 404 when you try http://httpbin.org/ip/ instead of http://httpbin.org/ip. (note the slash at the end)
So if you send your request to below URL, it should work I think.
http://localhost:8280/test/path/V1
Looks like you have not used API Context and/or its resource name, Please give a try with that otherwise, please provide your API Definition with back-end API details for further help.
Follow this tutorial to get an idea how to create an API. It is for APIM 2.0.0 but the skills are transferable.

I am getting Errors while JMS consuming in wso2esb

I am using wso2esb4.7.0 and ActiveMQ5.8.0 http://docs.wso2.org/display/ESB470/ESB+as+a+JMS+Producer and http://docs.wso2.org/display/ESB470/ESB+as+a+JMS+Consumer
according to the document i have done my messages are passing well to queue.Even storing also well .While conuming the messages in to the queue Wso2esb giving issues like formats
ERROR - JMSMessageReceiver Unknown error processing message
org.apache.axiom.om.OMException: com.ctc.wstx.exc.WstxUnexpectedCharException: Unexpected character '{' (code 123) in prolog; expected '<'
at [row,col {unknown-source}]: [1,1]
why this happening is there any message format issue i am passing just sample json like
curl -v -H "Accept: application/json" -H "Content-Type:application/json" -H "ModifiedOn:0" -H "username:vikaash|21405735755158656" -H "password:gbin" -d '{"name":"youtility tech","mail":"faisal.shaik#youtility.in"}' http://youtility2-desktop:8282/services/JmsStore
how we can send response to client
http://stackoverflow.com/questions/18440789/how-to-give-a-response-to-client-using-wso2esb-jmsqueue
Reason for this is, if you haven't specifically configure JMS Proxy to accept messages in a particular message format, it will always treat messages are in the text/xml format.
So when you send the message in application/json format you will get this exception while building the message. So if you want to accept messages in json format from a JMS queue you have to define 'transport.jms.ContentType' parameter as follows in the proxy service configuration.
<parameter name="transport.jms.ContentType">
<rules>
<jmsProperty>contentType</jmsProperty>
<default>application/json</default>
</rules>
</parameter>
Following is a sample proxy configuration.
<proxy name="StockQuoteProxy" transports="jms">
<target>
<inSequence>
<property action="set" name="OUT_ONLY" value="true"/>
</inSequence>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
<outSequence>
<send/>
</outSequence>
</target>
<publishWSDL uri="file:repository/samples/resources/proxy/sample_proxy_1.wsdl"/>
<parameter name="transport.jms.ContentType">
<rules>
<jmsProperty>contentType</jmsProperty>
<default>application/json</default>
</rules>
</parameter>
</proxy>