Consume an REST API through SOAP

PSX gives you the possibility to make an SOAP request against an REST API. This post will describe how this works in PSX and shows howto generate an SOAP client in Java which communicates with an REST API through SOAP.

How it works

If the incomming request contains an SOAPAction header PSX knows that it is an SOAP 1.1 request and sets the Content-Type header to applications/soap+xml (since SOAP 1.1 requests contain an text/xml Content-Type header) and the request method to the fragment value (if it is an valid request method i.e. GET or POST). PSX has an transformer registered with the applications/soap+xml Content-Type which handels an SOAP body. After this the request gets passed to the controller which then looks like an normal REST request. At the moment SOAP 1.2 requests are not supported because almost all tool support is build around SOAP 1.1 but if its needed it is also doable.

Generating an SOAP client in Java

As example we will create an Java SOAP client with Apache CXF which connects to the API from the PSX sample project. So first we have to setup the sample project through composer

php composer.phar create-project psx/sample .

If the project was installed you have to set the psx_url to the fitting url in the configuration.php file. After that you should reach the API at "[psx_url]/index.php/internet" and the WSDL file at "[url]/index.php/tool/wsdl/1/internet". Now we can generate the Java client based on the WSDL file. Therefor we use the wsdl2java tool to generate all needed Java classes.

wsdl2java [url]/index.php/tool/wsdl/1/internet

The generated classes can now be used to communicate with the REST API. Here an example howto get all entries

public class Main
{
    public static void main(String[] args)
    {
        CollectionService service = new CollectionService();
        CollectionPortType api = service.getCollectionPort();

        try
        {
            org.phpsx._2014.data.Collection collection = api.getCollection(new org.phpsx._2014.data.Void());

            for(int i = 0; i < collection.getEntry().size(); i++)
            {
                System.out.println("Region: " + collection.getEntry().get(i).getRegion() + " / " + collection.getEntry().get(i).getUsers());
            }
        }
        catch(FaultOutput e)
        {
            System.out.println(e.getMessage());
            System.out.println(e.getFaultInfo().getContext());
            System.out.println(e.getFaultInfo().getTrace());
        }
    }
}

If you would like to create a new entry you could use the following code. In the same way it is also possible to update and delete an entry.

public class Main
{
    public static void main(String[] args)
    {
        CollectionService service = new CollectionService();
        CollectionPortType api = service.getCollectionPort();

        try
        {
            Entry body = new Entry();
            body.setPlace(12);
            body.setPopulation(BigInteger.valueOf(1000));
            body.setRegion("Foobar");
            body.setUsers(BigInteger.valueOf(1000));
            body.setWorldUsers(20.4f);
            body.setDatetime(DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar()));
            
            Message resp = api.postEntry(body);
            
            if(resp.isSuccess())
            {
                System.out.println("Create entry successful");
            }
        }
        catch(FaultOutput e)
        {
            System.out.println(e.getMessage());
            System.out.println(e.getFaultInfo().getContext());
            System.out.println(e.getFaultInfo().getTrace());
        }
    }
}

Conclusion

Even the SOAP protocol is not so popular anymore because of its "complexity" I think it has the advantage that you can generate an client based on an description (WSDL) of the API. In the REST world we have at the moment not such an standard to describe an API but there are some projects like Swagger which try to do that. So we have to see whether such an standard gets established which then could be used to automatically generate client code.

Because of the possibility in PSX to accept SOAP requests we can make use of all the great tools to consume an SOAP service even if we are developing an REST API in the first place.