Sharing knowledge

How to add YAML support to go-restful

go-restful is a go package used for building REST-style web services. It is very powerful, but it supports JSON and XML out of the box only. Fortunately, go-restful allows to register custom serialization schemes.

To do so, it provides a handy interface EntityReaderWriter, which contains only two methods:

// EntityReaderWriter can read and write values using an encoding such as JSON,XML.
type EntityReaderWriter interface {
    // Read a serialized version of the value from the request.
    // The Request may have a decompressing reader. Depends on Content-Encoding.
    Read(req *Request, v interface{}) error

    // Write a serialized version of the value on the response.
    // The Response may have a compressing writer. Depends on Accept-Encoding.
    // status should be a valid Http Status code
    Write(resp *Response, status int, v interface{}) error
}

What we need to do is to implement this interface and register it in go-restful.

Let’s implement the interface:

package restyaml

import (
	"io"
	"io/ioutil"

	"github.com/emicklei/go-restful"
	"gopkg.in/yaml.v2"
)

// MediaTypeApplicationYaml is a Mime Type for YAML.
const MediaTypeApplicationYaml = "application/x-yaml"

// YamlReaderWriter implements EntityReaderWriter for YAML objects to be used by restful.
type YamlReaderWriter struct {
	contentType string
}

// NewYamlReaderWriter creates new instance.
func NewYamlReaderWriter(contentType string) restful.EntityReaderWriter {
	return YamlReaderWriter{contentType: contentType}
}

func closeWithErrHandle(c io.Closer) {
	err := c.Close()
	if err != nil {
		logger.Println("Unable to close resource: ", err)
	}
}

// Read a serialized version of the value from the request.
// The Request may have a decompressing reader. Depends on Content-Encoding.
func (e YamlReaderWriter) Read(req *restful.Request, v interface{}) error {
	defer closeWithErrHandle(req.Request.Body)
	bytes, err := ioutil.ReadAll(req.Request.Body)
	if err != nil {
		return err
	}
	err = yaml.Unmarshal(bytes, v)
	return err
}

// Write a serialized version of the value on the response.
// The Response may have a compressing writer. Depends on Accept-Encoding.
// status should be a valid Http Status code
func (e YamlReaderWriter) Write(resp *restful.Response, status int, v interface{}) error {
	bytes, err := yaml.Marshal(v)
	if err != nil {
		return err
	}

	resp.WriteHeader(status)
	_, err = resp.Write(bytes)
	return err
}

For implementing actual reading/writing of YAML I use library called go-yaml. The implementation is straightforward, just call Marshal and Unmarshal methods and do an error processing.

The final step is to register newly written YamlReaderWriter in go-restful container during application startup.

package rest

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"

	"bitbucket.org/uthark/yttrium/internal/config"
	"bitbucket.org/uthark/yttrium/internal/mime"
	"github.com/emicklei/go-restful"
)

// Init initializes server.
func init() {

	restful.SetLogger(logger)
	restful.DefaultResponseContentType(restful.MIME_JSON)
	restful.RegisterEntityAccessor(restyaml.MediaTypeApplicationYaml, restyaml.NewYamlReaderWriter(restyaml.MediaTypeApplicationYaml))

	// register web-services in restful and start http…
	// omitted for brevity
}

Now, we can submit requests in YAML format to our API:

$ curl -H "Accept: application/x-yaml" http://localhost:8080/task
- id: dd453ac9-6e8d-4f37-88a9-4e6d5b653e8d
  name: Another Task
  dateAdded: 2018-01-20T20:05:09.378Z
  dateCompleted: 0001-01-01T00:00:00Z

If we don’t specify header, the output will be in JSON:

$ curl http://localhost:8080/task
[
  {
   "id": "dd453ac9-6e8d-4f37-88a9-4e6d5b653e8d",
   "name": "Another Task",
   "dateAdded": "2018-01-20T20:05:09.378Z",
   "dateCompleted": "0001-01-01T00:00:00Z"
  }
 ]

If you have any questions, feel free to ping me on Twitter.

Migration to hugo completed

Good news, everyone. Migration from octopress to hugo was completed. If you find any broken layout and/or links, please contact me.

Refresh

Ok, hopefully I will start blog again soon.

Using Unitils ReflectionAssert

Often it is needed to compare two different instances of the class inside test. I.e. we save object into database, then fetch it back from db and we want to be sure if nothing was lost during saving/reading.

In order to make such assertions more easier and maintainable one can use great Unitils library which has useful class ReflectionAssert

First, update parent’s pom.xml:

<properties>
    <unitils.version>3.4</unitils.version>
</properties>
<dependency>
    <groupId>org.unitils</groupId>
    <artifactId>unitils-core</artifactId>
    <version>${unitils.version}</version>
    <scope>test</scope>
</dependency>

Then add dependency to the child module:

<dependency>
    <groupId>org.unitils</groupId>
    <artifactId>unitils-core</artifactId>
</dependency>

Usage is very simple: Add static import to the class.

import static org.unitils.reflectionassert.ReflectionAssert.assertReflectionEquals;

and use it instead of regular JUnit assert:

assertReflectionEquals(expected, actual);

It is possible to pass reflection comparator modes as optional parameters to the above method.

Be ware that this method is not very useful if you want to compare objects which has floating point or double parameters - ReflectionAssert compares double and float values using ==, so it is not very useful. It is not possible to pass epsilon for comparison.

excerpt from org.unitils.reflectionassert.comparator.impl.LenientNumberComparator#compare:

Double leftDouble = getDoubleValue(left);
Double rightDouble = getDoubleValue(right);
if (!leftDouble.equals(rightDouble)) {
    return new Difference(differenceMessage, left, right);
}

If you need to compare double values in JUnit assertions then it is better to use hamcrest library.

import static org.hamcrest.number.IsCloseTo.closeTo;
import static org.junit.Assert.assertThat;

// in @Test method:
assertThat(actual.getFederalIncomeTax(), closeTo(expected.getFederalIncomeTax(), EPSILON))

Happy hacking!

Using AssertJ

AssertJ is a library which provides fluent strongly-typed assertions to use in unit tests.

Example of assertions written with AssertJ:

import io.github.uthark.blog.assertj.Assertions.assertThat;

// ... within @Test
User result = userDao.findByLogin("username");
assertThat(result).
    isNotNull().
    isActive().
    hasLogin("username");

As you can see assertions look much more readable. The integration of assertj into Maven project is very easy:

  1. Update pom.xml in parent module
<properties>
    <assertj-core.version>1.6.0</assertj-core.version>
    <assertj-assertions-generator-maven-plugin.version>1.2.0</assertj-assertions-generator-maven-plugin.version>
</properties>

<dependencyManagement>
    <dependency>
        <groupId>org.assertj</groupId>
        <artifactId>assertj-core</artifactId>
        <version>${assertj-core.version}</version>
        <scope>test</scope>
    </dependency>
</dependencyManagement>

<pluginManagement>
    <plugin>
        <groupId>org.assertj</groupId>
        <artifactId>assertj-assertions-generator-maven-plugin</artifactId>
        <version>${assertj-assertions-generator-maven-plugin.version}</version>
        <executions>
            <execution>
                <id>generate-assertions</id>
                <phase>generate-test-sources</phase>
                <goals>
                    <goal>generate-assertions</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

</pluginManagement>
  1. Update pom.xml in child module
<dependencies>
    <dependency>
        <groupId>org.assertj</groupId>
        <artifactId>assertj-core</artifactId>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-assertions-generator-maven-plugin</artifactId>
            <configuration>
                <!-- you can define collection packages: -->
                <packages>
                    <param>io.github.uthark.blog.assertj</param>
                </packages>

                <!-- Or specify classes one by one. -->
                <classes>
                    <param>io.github.uthark.blog.assertj.User</param>
                </classes>
            </configuration>
        </plugin>
    </plugins>
</build>

After this changes it is possible to generate assertions for the classes you want test:

mvn assertj:generate-assertions

By default assertj will generate assertion classes in target/generated-test-sources/assertj-assertions/, it is possible to override this behaviour by passing configuration element targetDir to plugin.

Additonal documentation for Maven plugin can be found here

Happy hacking!

Initializing Mockito @Mocks with JUnit @Rule

In this post I will show how one can implement custom JUnit @Rule.

As an example let’s take Mockito and implement custom rule which will initialize Mocks in test class.

By default, Mockito provides the following methods of mock initialization:

  1. Using Mockito.mock

    Initialize mocks with Mockito.mock:

    public void FooTest {
            
        private Foo foo;
    
        @Before
        public void setUp() {
            FooDependency dep = Mockito.mock(FooDependency.class);
            foo = new Foo(dep);
        }
    }

    This is the simplest case.

  2. Using MockitoAnnotations. Initialize mocks with MockitoAnnotations:

    public void FooTest {
            
        private Foo foo;
    
        @Mock
        private FooDependency dep;
    
        @Before
        public void setUp() {
            MockitoAnnotations.initMocks(this);
            foo = new Foo(dep);
        }
    }

    This method is useful when you have a lot of mocks to inject.

  3. Using MockitoJUnitRunner

    Initialize mocks with MockitoJUnitRunner:

    @RunWith(MockitoJUnitRunner.class)
    public void FooTest {
            
        private Foo foo;
    
        @Mock
        private FooDependency dep;
    
        @Before
        public void setUp() {
            foo = new Foo(dep);
        }
    }

I want to show you another option, by using custom JUnit @Rule.

First, we need to implement TestRule interface which allows to implement custom behaviour during test execution:

MockitoInitializerRule:

public class MockitoInitializerRule implements TestRule {
    private Object test;

    public MockitoInitializerRule(Object test) {
        this.test = test;
    }

    @Override
    public Statement apply(Statement base, Description description) {
        return new MockitInitilizationStatement(base, test);
    }
}

We need to pass current test class instance to the rule, so it will be possible inject mocks into class instance. Actual implementation of our rule will go to new class - subclass of Statement:

MockitInitilizationStatement:

public class MockitInitilizationStatement extends Statement {
    private final Statement base;
    private Object test;

    MockitInitilizationStatement(Statement base, Object test) {
        this.base = base;
        this.test = test;
    }

    @Override
    public void evaluate() throws Throwable {
        MockitoAnnotations.initMocks(test);
        base.evaluate();
    }
}

What we do is basically initialize mocks in the test class and then proceed with the test method execution.

Now, let’s take a look at the usage of newly created Rule:

Example usage of MockitoInitializerRule:

public void FooTest {
    
    private Foo foo;

    @Mock
    private FooDependency dep;

    @Rule
    public TestRule mockitoInitializerRule = new MockitoInitializerRule(this);

    @Before
    public void setUp() {
        foo = new Foo(dep);
    }
}

Comparing to variant with MockitoJUnitRunner this one provides ability to use custom Runner, i.e. we can continue to use SpringJUnit4ClassRunner