Category Archives: REST

REST services with Mux and Go

Mux is a “powerful URL router and dispatcher” for Go and that means it allows us to route REST style requests to produce REST/micro services.

Creating our service

Let’s start out by creating a very simple EchoService which will contain our service implementation.

In my code based I create a service folder and add a service.go file, here’s the code

Note: This creation of a new go file, interface etc. is a little over the top to demonstrate mux routes/handlers, but my OO roots are probably showing through. In reality we just need a simple function with an expected signature – which we’ll see later.

package service

type IEchoService interface {
	Echo(string) string
}

type EchoService struct {

}

func (EchoService) Echo(value string) (string, error) {
	if value == "" {
		// create an error
		return "", nil
	}
	return value, nil
}

We’ve created an interface to define our service and then a simple implementation which can return a string and an error. For now we’ll not use the error, hence return nil for it.

Before we move onto the Mux code which will allow us to route requests/responses, let’s create a bare bones main.go file

package main

import (
   "goecho/service"
)

func main() {
   svc := service.EchoService{}
}

At this point this code will not compile because we haven’t used svc.

Implementing our router

Before we get started we need to run

go get -u github.com/gorilla/mux

from the shell/command prompt.

Now let’s add the code to create the mux router and to create a server on port 8080 that will be used to connect to our router (and service). We’ll also include code to log any fatal errors (again this code will not compile as the previously created svc variable remains unused at this point)

package main

import (
   "goecho/service"
   "github.com/gorilla/mux"
   "log"
   "net/http"
)

func main() {

   svc := service.EchoService{}

   router := mux.NewRouter()

   // service setup goes here

   log.Fatal(http.ListenAndServe(":8080", router))
}

I think this code is pretty self-explanatory, so we’ll move straight on to the implementation of our route and handler.

I’m going to add the handler to the service package but this handler needn’t be a method on the EchoService and could just be a function in the main.go (as mentioned previously).

You’ll need to add the following imports

import (
   "net/http"
   "github.com/gorilla/mux"
)

and then add this method, which is the handler and will call into our EchoService method.

func (e EchoService) EchoHandler(w http.ResponseWriter, r *http.Request) {
   vars := mux.Vars(r)

   result, _ := e.Echo(vars["s"])

   w.WriteHeader(http.StatusOK)
   w.Write([]byte(result))
}

To allow us to call the EchoService Echo method we declare a variable e for the EchoService. The arguments, of types ResponseWriter and Request are required to decode a request and to allow us to write a response. In this example the mux.Vars will be used to get us part of the rest command/URL.

Again, we’re not bothering (at this point to worry about the errors, so result, _ is used to ignore the error.

Next we write a Status OK code back and write the result back as a byte array.

Obviously we now need to set up our handler in main.go, so replace the line

// service setup goes here

with

router.HandleFunc("/echo/{s}", svc.EchoHandler).Methods("GET")

this simply creates the route for calls onto http://<hostname>/echo/??? (where ??? is any value which gets mapped to the mux.Vars[“s”]) through to the supplied handler (svc.EchoHandler) using the GET method.

For example, navigating to http://localhost:8080/echo/HelloWorld in your preferred web browser should display HelloWorld.

We can add multiple routes/handlers, for example let’s create a handler to respond with “Welcome to the EchoService” if the user navigates to http://localhost:8080. Place this function in main.go

func WelcomeHandler(w http.ResponseWriter, r *http.Request) {
   w.WriteHeader(http.StatusOK)
   w.Write([]byte("Welcome to the EchoService"))
}

and add this handler code before (or after) your existing handler code in main

router.HandleFunc("/", WelcomeHandler).Methods("GET")

Spring configuration for a JSON/XML REST service in Java

In Creating a CXF service that responds with JSON or XML and Creating a CXF client which can get JSON or XML we created a service and a client application for interacting with REST requests using XML or JSON as the body for the messages.

The Java guys love spring and beans, my code was all in Java source. So I’m going to show how to convert both the server and client into spring configurations.

In your client/server code add a resources folder to /src/main and within that add a new xml file, named whatever you like, mine’s spring-client.xml and spring-server.xml (for the client and server respectively).

Changes to the server

Let’s concentrate on the server first – our code looked like this

JAXRSServerFactoryBean factoryBean = new JAXRSServerFactoryBean();
factoryBean.setResourceClasses(SampleServiceImpl.class);
factoryBean.setResourceProvider(new SingletonResourceProvider(new SampleServiceImpl()));

Map<Object, Object> extensionMappings = new HashMap<Object, Object>();
extensionMappings.put("xml", MediaType.APPLICATION_XML);
extensionMappings.put("json", MediaType.APPLICATION_JSON);
factoryBean.setExtensionMappings(extensionMappings);

List<Object> providers = new ArrayList<Object>();
providers.add(new JAXBElementProvider());
providers.add(new JacksonJsonProvider());
factoryBean.setProviders(providers);

factoryBean.setAddress("http://localhost:9000/");
Server server = factoryBean.create();

The first thing we need to do is update our pom.xml to import spring, so add the following to the properties section

<spring.version>2.5.6</spring.version>

and then these dependencies

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>${spring.version}</version>
</dependency>

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring.version}</version>
</dependency>

Now change the Java code in our main method, replacing all the code which is listed above, to

ApplicationContext context = new ClassPathXmlApplicationContext("spring-server.xml");

Now we need to add the following to our spring-server.xml file

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jaxrs="http://cxf.apache.org/jaxrs"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
         http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">

    <jaxrs:server address="http://localhost:9000">
        <jaxrs:serviceBeans>
            <bean class="SampleServiceImpl" />
        </jaxrs:serviceBeans>
        <jaxrs:extensionMappings>
            <entry key="json" value="application/json"/>
            <entry key="xml" value="application/xml"/>
        </jaxrs:extensionMappings>
        <jaxrs:providers>
            <bean class="org.apache.cxf.jaxrs.provider.JAXBElementProvider" />
            <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
        </jaxrs:providers>
    </jaxrs:server>
</beans>

We’re using the jaxrs configuration to create our service beans which means the server is automatically created for us.

That’s it for the server.

Changes to the client

Let’s look at the existing client code

List<Object> providers = new ArrayList<Object>();
providers.add(new JAXBElementProvider());
providers.add(new JacksonJsonProvider());

SampleService service = JAXRSClientFactory.create(
   "http://localhost:9000", SampleService.class, providers);

WebClient.client(service)
   .type(MediaType.APPLICATION_JSON_TYPE)
   .accept(MediaType.APPLICATION_JSON_TYPE);

First off, we need to add spring to the pom.xml as we needed for the server, so duplicate the steps for updating the pom.xml as already outlined.

Next we replace our client code (above) with the following

ApplicationContext context = new ClassPathXmlApplicationContext("spring-client.xml");
SampleService service = (SampleService)context.getBean("client");

and finally put the following into the spring-client.xml file

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jaxrs="http://cxf.apache.org/jaxrs"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
         http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">

    <jaxrs:client id="client" address="http://localhost:9000" serviceClass="SampleService">
        <jaxrs:providers>
            <bean class="org.apache.cxf.jaxrs.provider.JAXBElementProvider" />
            <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
        </jaxrs:providers>
        <jaxrs:headers>
            <entry key="Accept" value="application/json" />
        </jaxrs:headers>
    </jaxrs:client>
</beans>

and that’s it – run the server, then run the client and all should work.

Note: I’ll leave it to the reader to add the relevant import statements

Building a REST service with Spring

I’ve been doing a fair bit with SOAP, REST and Java recently using CXF. A previous post demonstrated using CXF/JAXB to create a REST style service that returned either JSON or XML, let’s look at using Spring REST services to implement the same functionality.

Let’s start (as usual) with our pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>sample-rest-service</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.jayway.jsonpath</groupId>
            <artifactId>json-path</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <properties>
        <java.version>1.8</java.version>
    </properties>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>
</project>

Now we create our folder structure, so create the following from the root folder

src/main/java/demo

We’re going to need to code within the demo package.

Without the package you might see a warning “Your ApplicationContext is unlikely to start due to a @ComponentScan of the default package.”

Next up, we’ll create a service, or in Spring parlance, the controller

package demo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SampleController {

    @RequestMapping("/purchaseOrder")
    public PurchaseOrderType getPurchaseOrder() {
        return new PurchaseOrderType(1234);
    }
}

The PurchaseOrderType is simply the following

package demo;

public class PurchaseOrderType {

    private long _id;

    public PurchaseOrderType(long id) {
        _id = id;
    }

    public long getId() {
        return _id;
    }
}

Now we need the application to start the service

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

To run this we can, ofcourse, set up a configuration or from the Terminal window run

mvn spring-boot:run

Now, if we navigate to http://localhost:8080/purchaseOrder/ we should see

{"id":1234}

Now, let’s extend this to allow us to return XML. We’ll need to annotate PurchaseOrderType with the @XmlRootElement, we’ll also need a default constructor and a setter for our Id property

package demo;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class PurchaseOrderType {

    private long _id;

    public PurchaseOrderType() {
    }

    public PurchaseOrderType(long id) {
        _id = id;
    }

    public long getId() {
        return _id;
    }

    public void setId(long id) {
        _id = id;
    }
}

Changing the port of the Tomcat server

You may have noticed that when running this application we get an instance of a Tomcat server running, by default it uses port 8080, but what about if we need/want to change this. We can create an EmbeddedServletContainerCustomizer, as below.

package demo;

import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.stereotype.Component;

@Component
public class ApplicationContainer implements EmbeddedServletContainerCustomizer {

    @Override
    public void customize(ConfigurableEmbeddedServletContainer configurableEmbeddedServletContainer) {
        configurableEmbeddedServletContainer.setPort(8888);
    }
}

Code is available here https://github.com/putridparrot/blog-projects/tree/master/spring-rest

Hosting more than one service using CXF and Jetty

This is a logical “next post” to Hosting a CXF SOAP webservice in an existing Jetty instance.

Let’s look at what’s need to host more than one service using CXF from a running instance of Jetty.

Changes to our SOAP Service

We’re going to do this by hosting our original HelloWorld service (from the previous post) with a single line change and alongside it we’ll create a REST service.

So in the AppConfig from the previous post, rename getService to getSoapServer (or whatever you like) and the code should look like this

@Bean @DependsOn( "cxf" )
public Server getSoapServer() {
   JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
   factory.setServiceBean(new HelloWorldImpl());
   factory.setAddress("/soap");
   return factory.create();
}

Apart from the method name change, we’ve added a setAddress call with a relative path. If you recall from the previous post our Jetty server will run on port 9000, i.e. http://localhost:9000 but now our SOAP service will be on http://localhost:9000/soap/HelloWorld?wsdl.

Adding a REST Service

Update the pom.xml with the following, in the properties we’ll add

<json.version>1.1.0-M1</json.version>
<glassfish.version>1.0.4</glassfish.version>

and these dependencies

<dependency>
   <groupId>javax.json</groupId>
   <artifactId>javax.json-api</artifactId>
   <version>${json.version}</version>
</dependency>

<dependency>
   <groupId>org.apache.cxf</groupId>
   <artifactId>cxf-rt-frontend-jaxrs</artifactId>
   <version>${cxf.version}</version>
</dependency>

<dependency>
   <groupId>org.apache.cxf</groupId>
   <artifactId>cxf-rt-rs-extension-providers</artifactId>
   <version>${cxf.version}</version>
</dependency>

<dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>javax.json</artifactId>
   <version>${glassfish.version}</version>
</dependency>

Next we’ll create a simple REST service (I’ll actually duplicate the one from here).

So create a new Java class, mine’s named PeopleService and here’s the code

package com.putridparrot.core;

import javax.json.JsonArray;
import javax.json.Json;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/people")
public class PeopleService {
    @Produces({"application/json"})
    @GET
    public JsonArray getPeople() {
        return Json.createArrayBuilder()
                .add(Json.createObjectBuilder()
                        .add("firstName", "Brian")
                        .add("lastName", "Kernighan "))
                .add(Json.createObjectBuilder()
                        .add("firstName", "Dennis")
                        .add("lastName", "Ritchie "))
                .add(Json.createObjectBuilder()
                        .add("firstName", "Bjarne")
                        .add("lastName", "Stroustrup"))
                .build();
    }
}

within AppConfig, place the following

@Bean @DependsOn( "cxf" )
public Server getRestServer() {
   JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
   factory.setServiceBean(new PeopleService());
   factory.setProvider(new JsrJsonpProvider());
   factory.setAddress("/rest");
   return factory.create();
}

if you run the App.main, you should be able to navigate to http://localhost:9000/soap/HelloWorld?wsdl to get the SOAP service’s wsdl and http://localhost:9000/rest/people to get the results of the PeopleService call.

Just to complete the picture – the PeopleService is given a path to the REST calls. We’re simply returning JSON and so we annotate with the @Produces line. As we’re only support a GET call to this service we annotate @GET. Within the getPeople method we build up a JSON document and that’s all there is to it.