REST Data Services with WSO2

Daniel S. Blanco
3 min readMar 14, 2020

--

If you know something of WSO2, you will know that you can create easily web services with a database as the backend, also known as data services. These data services by default are called as SOAP services. But WSO2 Data services are prepared to be invoked as REST services.

We will explain how to do it with one example per each HTTP method. But prior to that, you need to have already configured a data source previously. In our example that data source will be called LIBRARY.

In the code section below, you can see a basic example of a data service, configure with our data source and a query sample.

<data name="book_dataservices" transports="http https local">
<config id="LIBRARY">
<property name="carbon_datasource_name">LIBRARY</property>
</config>
<query id="getBook" useConfig="LIBRARY">
<sql>SELECT NAME, AUTHOR FROM BOOK WHERE ID = :id</sql>
<result element="Books" rowName="book">
<element column="NAME" name="name" xsdType="STRING"/>
<element column="AUTHOR" name="author" xsdType="STRING"/>
</result>
<param name="id" ordinal="1" sqlType="INTEGER"/>
</query>
</data>

For now, this data service can not do anything by itself. We will need to add an operation or a resource element. And here it will be the difference between having a REST data service or not. The operation element lets us SOAP invocations and the resource lets REST invocations.

But before to create a resource element in the data service you must know some terms to configure it:

  • resource path: the context to call the date services. Here you can also configure query params.
  • resource method: the HTTP method to invoke it.
  • query id: the id of the query associated with the resource.
  • query params: the association between params from the resource and the query.

Now, we can see a resource configured for the previous query. The necessary param for the query getBook, it will be configured as a query param.

<resource method="GET" path="book/{id}">
<call-query href="getBook">
<with-param name="id" query-param="id"/>
</call-query>
</resource>

To invoke it, we can use the following curl command. Remember book_dataservices is our data service name.

curl -kX GET 'https://localhost:8243/services/book_dataservices/book/3' \
-H 'Accept: application/json'

The following is an example of an HTTP Post call.

<query id="postBook" keyColumns="ID" returnGeneratedKeys="true" useConfig="LIBRARY">
<sql>INSERT INTO BOOK (NAME, AUTHOR) VALUES (?, ?)</sql>
<result element="return" rowName="" useColumnNumbers="true">
<element column="1" name="ID" xsdType="integer"/>
</result>
<param name="name" ordinal="1" sqlType="STRING"/>
<param name="author" ordinal="2" sqlType="STRING"/>
</query>
<resource method="POST" path="book">
<call-query href="postBook">
<with-param name="name" query-param="name"/>
<with-param name="author" query-param="author"/>
</call-query>
</resource>

The main difference to invoke it’s how to pass the query params. For that, we need to create a JSON payload, but this payload must have a specific format. This payload is a JSON object composed of an underscore with the name of the HTTP method (in this case it will be _post) and the resource attribute context (each slash will be translated to an underscore also).

curl -kX POST 'https://localhost:8243/services/book_dataservices/book' \
-H 'Content-Type: application/json' -H 'Accept: application/json' \
--data-raw '{ "_postbook": { "name": "AT", "author": "AT" } }'

The PUT method will be very similar to the POST method.

<query id="putbook" returnUpdatedRowCount="true" useConfig="LIBRARY">
<sql>UPDATE BOOK SET NAME=?, AUTHOR=? WHERE ID = ?</sql>
<result element="UpdatedRowCount" rowName="" useColumnNumbers="true">
<element column="1" name="ID" xsdType="integer"/>
</result>
<param name="name" sqlType="STRING"/>
<param name="author" sqlType="STRING"/>
<param name="id" sqlType="INTEGER"/>
</query>
<resource method="PUT" path="book">
<call-query href="putbook">
<with-param name="name" query-param="name"/>
<with-param name="author" query-param="author"/>
<with-param name="id" query-param="id"/>
</call-query>
</resource>

We can test it with the following command:

curl -kX PUT 'https://localhost:8243/services/book_dataservices/book' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
--data-raw '{"_putbook": {"name": "AT1","author": "AT1","id":3 } }'

And finally the HTTP Delete resource:

<query id="deleteBook" useConfig="LIBRARY">
<sql>DELETE FROM BOOK WHERE ID = :id</sql>
<result element="UpdatedRowCount" rowName="" useColumnNumbers="true">
<element column="1" name="ID" xsdType="integer"/>
</result>
<param name="id" ordinal="1" sqlType="INTEGER"/>
</query>
<resource method="DELETE" path="book/{id}">
<call-query href="deleteBook">
<with-param name="id" query-param="id"/>
</call-query>
</resource>

An example of the invocation will be:

curl -kX DELETE 'https://localhost:8243/services/book_dataservices/book' \
-H 'Accept: application/json' -H 'Content-Type: application/json' \
--data-raw '{ "_deletebook": { "id": 3 } }'

It’s very important to be conscientious about the Accept and Content-Type HTTP headers, and in which cases we must use them or not. This can be the difference between that the invocation works correctly or not.

--

--

No responses yet