Programming with Java APIs, Part 2: API definitions

Use API definitions to generate a Spring Web MVC app with an Angular 2 frontend

jw api driven dev2
moonjazz (CC BY-SA 2.0)

The first half of this article introduced the big picture of programming with Java APIs--such as how Java APIs fit into application development, cloud and microservices architectures, and the role of API specs like OpenAPI. You were introduced to OpenAPI and we developed a simple example application built from an API definition.

In this article we'll continue developing our Java API definitions and application code with OpenAPI and Swagger, and we'll throw Swing Web MVC and Angular 2 into the mix. By the end of the article, we'll have used Swagger tools to both generate OpenAPI from a Spring MVC app, and generate an Angular frontend from an OpenAPI specification. You will be familiar with the core Swagger tools, and you'll know how to use them to build your own API-driven Java web apps.

Swagger and OpenAPI

As you might recall from Part 1, Swagger and OpenAPI are closely related. In fact, Swagger started out as the API definition language now known as OpenAPI. Over time, Swagger has evolved into a rich ecosystem of related projects, each one supporting the OpenAPI specification. Swagger includes a visual API designer and a handful of commercial integration products that are built on top of open source components.

Java API definitions

In Part 1, I explained the distinction between prescriptive and descriptive API use. In a prescriptive definition, the API drives code creation, whereas in a descriptive definition, we use code to generate the API. You also might see this distinction described in terms of design-first or implementation-first API usage. Both styles are valid and useful, and they are equally supported by tooling. We'll use both prescriptive and descriptive API definitions in this article.

For prescriptive API-driven development, Swagger offers the Codegen project. Codegen is able to parse an OpenAPI definition and generate code to support it, such as URL endpoint handlers and the different models defined by API paths and schemas. (See Part 1 to refresh your memory about the anatomy of an OpenAPI defintion, including the role of paths and schemas.)

The Codegen project provides a command-line interface (CLI), which is a framework for plugins supporting output to various technologies. Codegen includes a Node.js plugin that generates Node.js code, a Spring plugin for Spring-based Java, and so forth.

For descriptive API-driven development, the swagger-core project supports interacting with OpenAPI from Java. Building on swagger-core, the swagger-servlet project enables outputting OpenAPI definitions from Java servlets. Other languages and stacks offer a variety of additional approaches within the Swagger ecosystem.

Swagger with Spring Web MVC

Swagger is the bridge between the OpenAPI standard and a wide range of technologies. For the purpose of this article, we'll use Swagger in a Spring Web MVC application that integrates with Spring Boot for project automation. Later in the article we'll incorporate a a frontend built with Angular 2.

In order to work with Spring, we need a project in the Swagger ecosystem that handles Spring. One of the best is SpringFox, which builds on swagger-core to integrate Spring-based applications.

An explicit goal of SpringFox is to integrate with Spring-based apps without requiring modifications to Spring's application code or annotations. The annotations that define request mappings also drive API generation. This is a forward-looking approach, as tools become intelligent enough to understand the technology in use without intervention from the developer.

The example app

Swagger interacts with both backend and frontend code. We're going to start with the backend. We'll take a descriptive approach by creating our initial Java API definition from existing code, then we'll turn around and use a prescriptive approach to generate server-side stubs from a Java API definition.

The first thing we want to do is create a Spring-based RESTful service. Since this isn't a Spring tutorial, we'll just use an existing app: Spring Boot's Hello World example.

To obtain this project, run git clone https://github.com/spring-guides/gs-rest-service.git on your command line. That will pull down the project. Inside you will see a /complete directory with a simple Spring-based RESTful service.

Built with Spring Boot and Spring's Web MVC framework, this simple project consists of three classes:

  • Application, used to configure the app infrastructure
  • Greeting, a model class
  • GreetingController, a resource mapping

Thanks to Spring Boot's simplified configuration, all you need to set up Spring Web MVC in Application.java is the code in Listing 1.

Listing 1. Unmodified Application.java


@Spring BootApplication
public class Application {

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

All that is required to trigger Spring is the @Spring BootApplication annotation. With Spring Web MVC already included in the dependencies, Spring Boot automatically wires the application as a Spring Web MVC project. In the main method, a call to SpringApplication.run starts the app, which is just a standard Java class.

The app doesn't require packaging as a WAR file and deployment into an external container, although that is supported. Instead, the app will run as a standalone Java program that uses an embedded container; in this case Tomcat.

Running the server

Now let's run the project. At the command line, cd to the project directory at /gs-rest-service/complete/, and you can build and run the project with either Maven or Gradle. I'm using Maven. Simply type mvn spring-boot:run, and the app will run with the embedded Tomcat server.

Once it's running, you can try the available endpoint in your browser; just enter: http://localhost:8080/greeting. You'll receive a simple JSON response. You can also add a parameter, like so: http://localhost:8080/greeting?name=George Harrison. With this parameter, you will receive a greeting for the quietest Beatle.

As I mentioned, this API is very simple, but it has the essential elements: a model suggesting an API schema, an endpoint, and parameter support. Our next step is to get an OpenAPI definition from this code.

Generating a Java API definition from code

We'll make two changes to the existing app to get our Java API definition. First, we'll modify pom.xml to add a repository and a dependency.

In the repositories element, add Listing 2.

Listing 2. Adding the SpringFox repository


<repository>
  <id>jcenter-snapshots</id>
  <name>jcenter</name>
  <url>https://jcenter.bintray.com/</url>
</repository>

In the dependencies element, add Listing 3.

Listing 3. Adding basic API support to Application.java


<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.6.1</version>
</dependency>

These changes will add Swagger support to the project via SpringFox. Now you can return to Application.java (from Listing 1) and make the modification shown in Listing 4.

Listing 4. Add basic API support to Application.java


import springfox.documentation.swagger2.annotations.EnableSwagger2;
//...
@Spring BootApplication
@EnableSwagger2
public class Application {

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

Next, you need to create a Spring bean that will be auto-wired into the system. The Spring bean will let you configure Swagger's global settings. Add Listing 5 to the code in Application.java.

Listing 5. Creating a SpringFox Docket bean in Application.java


@Bean
    public Docket petApi() {
      return new Docket(DocumentationType.SWAGGER_2)
          .select()
            .apis(RequestHandlerSelectors.any())
            .paths(PathSelectors.any())
            .build();
    }

This is a simple configuration for the auto-wired Docket class. SpringFox uses Docket to configure the many parameters available in OpenAPI.

The Swagger endpoints

Now when you run the project, you will see some new endpoints are available. We are most interested in http://localhost:8080/v2/api-docs. Check that endpoint and you will see JSON output. That is the OpenAPI definition for the example app.

Looking back at Listing 5, notice that you have the ability to filter what APIs are active. You can filter by both apis and paths. There are many more settings you can adjust to manipulate the API definition. For example, you could use pathMapping("/") to establish a servlet path mapping.

Setup the Swagger UI

Enabling Swagger's UI will give you a nicer way to look at the API definition.

Return to your pom.xml and add Listing 6 to the dependencies.

Listing 6. SpringFox UI dependency


<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.6.1</version>
</dependency>

Once you've added the springfox-swagger-ui to the project, you can rebuild your app with mvn clean package, then run it again with mvn spring-boot:run. Now you'll see a new URL is available: http://localhost:8080/swagger-ui.html. When you visit that URL, you should see something like the screenshot in Figure 1.

api driven dev fig1 Matthew Tyson

Figure 1. The Swagger UI

Looking at the UI in Figure 1, you can see the /greeting endpoint is represented, along with its HTTP methods. Each method can be opened for more detail. Figure 2 shows detail for the /greeting GET method.

api driven dev fig2 Matthew Tyson

Figure 2. Swagger UI endpoint detail

The model is represented, along with the parameters that are accepted. Clicking the Try it out! button sends a simple request to the endpoint.

Generating server-side code

So far you've seen how to create a basic OpenAPI definition from an existing Spring Web MVC app. You've also viewed the definition using a Swagger UI. Notice that you were able to get a huge amount of information out of the existing application without adding any special metadata to the application internals, except the one simple @EnableSwagger2 annotation.

Next we'll turn the flow around and see how we can use Swagger to generate code from an API spec.

Server stubbing

The Swagger ecosystem includes numerous plugins that support generating server stubs from OpenAPI specs. There are plugins for numerous languages and frameworks, and one of these is Spring Boot.

To start, take a look at this sample API hosted by the Swagger project in your browser: http://petstore.swagger.io/v2/swagger.json.

This API definition is (yet another) manifestation of the classic PetStore example app; in this case, the OpenAPI specification for an online Pet Store application.

Installing the Swagger CLI

Swagger's code generation features are available via an executable JAR file that provides a command-line interface. To install the CLI, download the JAR file. Note that you'll be executing this JAR from a command prompt.

Generate a server stub from a Java API

Next you'll generate a server stub for the PetStore API. Remember to align the version number in the code below with that of the JAR you've just downloaded.

Listing 7. Using the Swagger CLI to create a Spring stub


java -jar [path-to-swagger-jar]/swagger-codegen-cli-2.2.2.jar generate \
  -i http://petstore.swagger.io/v2/swagger.json \
  -l spring \
  -o output-directory/
  
  

Command-line options for generating the stub are as follows:

  • -i indicates where the API definition is located; this can be either a file or a URL.
  • -l indicates what output format to use.
  • -o tells the CLI where to put the generated source code.

In this case, we're running the CLI with spring as the -l switch. As a result, you'll see application output with a similar structure to the Spring Boot Hello World application. This kind of functionality, where endpoints are automatically generated, is useful for stubbing out a new application when you already have a well-defined API spec.

Integrating server stubbing into a Maven build

If you want to add to an existing app in an ongoing way, you can integrate Swagger's codegen functionality into your build via a Maven plugin. Returning to the pom.xml for the Hello World app, add the plugin defined in Listing 8.

Listing 8. Using the Swagger CLI to create a Spring stub


<plugin>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-codegen-maven-plugin</artifactId>
    <version>2.2.2-SNAPSHOT</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <inputSpec>http://petstore.swagger.io/v2/swagger.json</inputSpec>
                <language>spring</language>
                <configOptions>
                    <sourceFolder>src/gen/java/main</sourceFolder>
                </configOptions>
            </configuration>
        </execution>
    </executions>
</plugin>
1 2 Page 1
Page 1 of 2