Show Navigation

Consume and test a third-party REST API

Use Ersatz, a "mock" HTTP library, for testing code dealing with HTTP requests

Authors: Sergio del Amo

Grails Version: 4

1 Grails Training

Apache Grails Training

Apache Grails is now part of the Apache Software Foundation. The community-maintained training catalog is being migrated; in the meantime see the Learning page for current resources, recorded talks, and links to other community-supplied training material.

2 Getting Started

In this guide you are going to create a Grails app which consumes a third party REST API. Moreover, we will use a "mock" HTTP library to test the code which interacts with this external service.

2.1 What you will need

To complete this guide, you will need the following:

  • Some time on your hands

  • A decent text editor or IDE

  • JDK 11 or greater installed with JAVA_HOME configured appropriately

2.2 How to complete the guide

To get started do the following:

or

The Grails guides repositories contain two folders:

  • initial Initial project. Often a simple Grails app with some additional code to give you a head-start.

  • complete A completed example. It is the result of working through the steps presented by the guide and applying those changes to the initial folder.

To complete the guide, go to the initial folder

  • cd into grails-guides/grails-mock-http-server/initial

and follow the instructions in the next sections.

You can go right to the completed example if you cd into grails-guides/grails-mock-http-server/complete

3 Writing the Application

The first step is to add the Micronaut HTTP client library to our project. Add the next dependency:

build.gradle
link:{sourcedir}/build.gradle[role=include]

If you are a windows user you need to have this in build.gradle:

build.gradle
webdriverBinaries {
    chromedriver {
        version = '77.0.3865.40'
        architecture = 'X86'
    }
    geckodriver '0.24.0'
}

3.1 Open Weather Map

OpenWeatherMap is a web application which offers an API which allows you to:

Get current weather, daily forecast for 16 days, and 3-hourly forecast 5 days for your city. Helpful stats, graphics, and this day in history charts are available for your reference. Interactive maps show precipitation, clouds, pressure, wind around your location.

They have a FREE plan which allows you to get the Current Weather Data of a city.

After you register, you get an API Key. You will need an API key to interact with the Open Weather Map API.

apiKey
the API key may take several minutes to become active.

3.2 Parse Response into JAVA classes

Create several JAVA POJOs (Plain Old Java Objects) to map the OpenWeatherMap JSON response to classes.

src/main/java/org/openweathermap/CurrentWeather.java
link:{sourcedir}/src/main/java/org/openweathermap/CurrentWeather.java[role=include]
//getters and setters
}
src/main/java/org/openweathermap/Clouds.java
link:{sourcedir}/src/main/java/org/openweathermap/Clouds.java[role=include]
//getters and setters
}
src/main/java/org/openweathermap/Coordinate.java
link:{sourcedir}/src/main/java/org/openweathermap/Coordinate.java[role=include]
//getters and setters
}
src/main/java/org/openweathermap/Rain.java
link:{sourcedir}/src/main/java/org/openweathermap/Rain.java[role=include]
//getters and setters
}
src/main/java/org/openweathermap/Unit.java
link:{sourcedir}/src/main/java/org/openweathermap/Unit.java[role=include]
src/main/java/org/openweathermap/Weather.java
link:{sourcedir}/src/main/java/org/openweathermap/Weather.java[role=include]
//getters and setters
}
src/main/java/org/openweathermap/Sys.java
link:{sourcedir}/src/main/java/org/openweathermap/Sys.java[role=include]
//getters and setters
}
src/main/java/org/openweathermap/Wind.java
link:{sourcedir}/src/main/java/org/openweathermap/Wind.java[role=include]
//getters and setters
}

3.3 Open Weather Service

Create the next service:

grails-app/services/org/openweathermap/OpenweathermapService.groovy
link:{sourcedir}/grails-app/services/org/openweathermap/OpenweathermapService.groovy[role=include]

link:{sourcedir}/grails-app/services/org/openweathermap/OpenweathermapService.groovy[role=include]
link:{sourcedir}/grails-app/services/org/openweathermap/OpenweathermapService.groovy[role=include]
}
1 To get the current weather, do a GET request providing the city name, country code and API Key as query parameters.
2 In case of a 200 - OK - response, parse the JSON data into Groovy classes.
3 if the answer is not 200. For example, 401; the method returns null.

The previous service uses several configuration parameters. Define them in application.yml

grails-app/conf/application.yml
link:{sourcedir}/grails-app/conf/application.yml[role=include]

3.4 Ersatz

To test the networking code, add a dependency to Ersatz

build.gradle
link:{sourcedir}/build.gradle[role=include]

Ersatz Server is a "mock" HTTP server library for testing HTTP clients. It allows for server-side request/response expectations to be configured so that your client library can make real HTTP calls and get back real pre-configured responses rather than fake stubs.

First, implement a test which verifies that the OpenweathermapService.currentWeather method returns null when the REST API returns 401. For example, when the API Key is invalid.

src/test/groovy/org/openweathermap/OpenweathermapServiceSpec.groovy
link:{sourcedir}/src/test/groovy/org/openweathermap/OpenweathermapServiceSpec.groovy[role=include]

link:{sourcedir}/src/test/groovy/org/openweathermap/OpenweathermapServiceSpec.groovy[role=include]
}
1 Declare expectations, a GET request to the OpenWeather path with query parameters.
2 Declare conditions to be verified, in this example we want to to verify the endpoint is hit only one time.
3 Tell the mock server to return 401 for this test.
4 Ersatz starts an embedded Undertow server, root the networking requests to this server instead of to the OpenWeather API server.
5 Verify the ersatz servers conditions.
6 Rember to stop the server

Next, test that when the server returns 200 and a JSON payload, the JSON payload is parsed correctly into Groovy classes.

src/test/groovy/org/openweathermap/OpenweathermapServiceSpec.groovy
link:{sourcedir}/src/test/groovy/org/openweathermap/OpenweathermapServiceSpec.groovy[role=include]

link:{sourcedir}/src/test/groovy/org/openweathermap/OpenweathermapServiceSpec.groovy[role=include]

}
1 Declare a response encoder to convert a Map into application/json content using an Ersatz-provided encoder.
2 Define the response content as a Map which will be converted to JSON by the defined encoder (above).

Shadow Jar section of the Ersatz User Guide: The embedded version of Undertow used by Ersatz has caused issues with some server frameworks which also use Undertow (e.g. Grails, and Spring-boot). If you run into errors using the standard jar distribution, please try using the safe distribution, which is a shadowed jar which includes the Undertow library and its JBoss dependencies repackaged in the jar. _

3.5 Run Tests

To run the tests:

./grailsw
grails> test-app
grails> open test-report

or

./gradlew check
open build/reports/tests/index.html

3.6 Root Url to Weather Controller

Create a HomeController which uses the previous service:

grails-app/controllers/demo/HomeController.groovy
link:{sourcedir}/grails-app/controllers/demo/HomeController.groovy[role=include]

In UrlMapping.groovy map the root URL to this controller:

"/"(controller: 'home')`

3.7 TagLib

Create a taglib to help you, to encapsulate some rendering aspects:

grails-app/taglib/org/openweathermap/OpenweathermapTagLib.groovy
link:{sourcedir}/grails-app/taglib/org/openweathermap/OpenweathermapTagLib.groovy[role=include]

3.8 View

Create the next GSPs to render the gathered Weather information as an HTML page.

grails-app/views/home/index.gsp
link:{sourcedir}/grails-app/views/home/index.gsp[role=include]
grails-app/views/openweather/_currentWeather.gsp
link:{sourcedir}/grails-app/views/openweather/_currentWeather.gsp[role=include]

Add the next CSS snippet to style the weather forecast.

grails-app/assets/stylesheets/main.css
.weatherBlock {
     width: 150px;
     height: 200px;
     margin: 10px auto;
     text-align: center;
     border: 1px solid #c0d3db;
     float: left;
}

4 Running the Application

To run the application use the ./gradlew bootRun command which will start the application on port 8080.

If you setup a valid API Key in application.yml, you will see the London weather prediction.

homepage

5 Help with Grails

Help with Apache Grails

Apache Grails is supported by an active community of contributors and the Apache Software Foundation. If you need help working through a guide, want to discuss the framework, or have run into something that looks like a bug, the channels below are the right place to start.

For Grails plugins, see the matching project on the apache org or the plugin’s own GitHub repository.