Skip to content

JAX RS Application

Vojtěch Habarta edited this page Mar 20, 2017 · 4 revisions

typescript-generator has support for JAX-RS application:

  1. It can discover REST resource and JSON classes used in JAX-RS REST service.
  2. It can generate client for JAX-RS REST service. Currently client can be:
  • Axios client implementation usable out of the box (AxiosClientExtension extension)
  • generic client class which delegates requests to some library (generateJaxrsApplicationClient parameter)
  • or just TypeScript interface (generateJaxrsApplicationInterface parameter)

You can start with this Maven example which automatically discovers REST resources and generates Axios service client:

<configuration>
    <outputFileType>implementationFile</outputFileType>
    <outputKind>module</outputKind>
    <classesFromAutomaticJaxrsApplication>true</classesFromAutomaticJaxrsApplication>
    <extensions>
        <extension>cz.habarta.typescript.generator.ext.AxiosClientExtension</extension>
    </extensions>
</configuration>

Below are details of 1. class discovery and 2. generated clients.

1. Class discovery from JAX-RS application

Class discovery is convenient way how to specify which classes should be processed.

For example from this REST resource class:

@Path("user")
public class UserResource {
    @GET
    public User getCurrentUser() {}
}

typescript-generator can discover JSON class User and generate TypeScript declaration for it.

Resource classes can either be found automatically or using JAX-RS application class.

Automatic JAX-RS application

Automatic way can be turned on using classesFromAutomaticJaxrsApplication parameter. Here is Maven configuration snippet:

<configuration>
    <classesFromAutomaticJaxrsApplication>true</classesFromAutomaticJaxrsApplication>
</configuration>

Specific application class

If automatic way doesn't work as needed you can configure specific Application class from which typescript-generator can get list of classes. In previous versions this could be configured using classesFromJaxrsApplication parameter but now Application class is also used when it is reached using classes or classPatterns parameter.

Example JAX-RS application:

public class TestApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        return new LinkedHashSet<Class<?>>(Arrays.asList(
                UserResource.class
        ));
    }
}

and snippet for Maven:

<configuration>
    <classes>
        <class>cz.habarta.TestApplication</class>
    </classes>
</configuration>

Application constructor

When application class is parsed it must have no-argument constructor which should not have any side-effects like communication with database, starting new threads etc.

If your application has constructor with parameters you can add second constructor (can be private) or second application (possibly with inheritance).

Application class doesn't have to derive directly from javax.ws.rs.core.Application, it can derive from some framework class like org.glassfish.jersey.server.ResourceConfig in Jersey.

Maven Guice conflict

If there is a guice version conflict between your application and typescript-generator-maven-plugin either

  1. remove guice initialization from no-argument constructor or
  2. add following dependency to the plugin.
<plugin>
    <groupId>cz.habarta.typescript-generator</groupId>
    <artifactId>typescript-generator-maven-plugin</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.sonatype.sisu</groupId>
            <artifactId>sisu-guice</artifactId>
            <version>3.2.6</version>
        </dependency>
    </dependencies>
</plugin>

2. JAX-RS application client

This feature provides convenient way how to use REST service from TypeScript. Typescript-generator generates client class with methods that has typed parameters and return types and make HTTP requests to particular URL path.

Client class for JAX-RS service can be generated using generateJaxrsApplicationClient configuration parameter.

Let's see example. For this resource:

@Path("people/{personId}")
private static class PersonResource {

    @PathParam("personId")
    protected long personId;

    @GET
    public Person getPerson() {
        return null;
    }

    @GET
    @Path("address/{addressId}")
    public Address getAddress(@PathParam("addressId") long addressId) {
        return null;
    }

}

following client class will be generated:

class RestApplicationClient {

    constructor(private httpClient: HttpClient) {
    }

    getPerson(personId: number): RestResponse<Person> {
        return this.httpClient.request({ method: "GET", url: `api/people/${personId}` });
    }

    getAddress(personId: number, addressId: number): RestResponse<Address> {
        return this.httpClient.request({ method: "GET", url: `api/people/${personId}/address/${addressId}` });
    }

}

Here is Maven example how to use this functionality:

<configuration>
    <outputFileType>implementationFile</outputFileType>
    <outputKind>module</outputKind>
    <classesFromAutomaticJaxrsApplication>true</classesFromAutomaticJaxrsApplication>
    <generateJaxrsApplicationClient>true</generateJaxrsApplicationClient>
</configuration>

HttpClient adapter

Generated client class delegates requests to some HttpClient adapter which is set in constructor and can be implemented using arbitrary HTTP API or library like XMLHttpRequest, jQuery, axios, Angular etc.

This is HttpClient interface definition:

interface HttpClient {
    request(requestConfig: { method: string; url: string; queryParams?: any; data?: any; }): RestResponse<any>;
}

This interface can be implemented in typescript-generator extension (like cz.habarta.typescript.generator.ext.AxiosClientExtension) or in user code.

Note that you can create multiple instances of client class. This can be useful for example for tests running in Node.js where each client can have different logged-in user cookie or header.

Customization

Return type

Methods have RestResponse return type which is by default defined as:

type RestResponse<R> = Promise<R>;

This definition can be configured using restResponseType parameter.

Additional request options

Using restOptionsType parameter it is possible to pass additional options to request methods.

Customization example

Customization parameters can be combined with importDeclarations or referencedFiles parameter to use types from some library. Here is Maven example with customization for axios library:

<configuration>
    <outputFileType>implementationFile</outputFileType>
    <outputKind>module</outputKind>
    <classesFromAutomaticJaxrsApplication>true</classesFromAutomaticJaxrsApplication>
    <generateJaxrsApplicationClient>true</generateJaxrsApplicationClient>
    <importDeclarations>
        <import>import axios from "axios"</import>
        <import>import { AxiosRequestConfig, AxiosPromise } from "axios"</import>
    </importDeclarations>
    <restOptionsType>AxiosRequestConfig</restOptionsType>
    <restResponseType>AxiosPromise</restResponseType>
</configuration>

Options for grouping operations (namespacing)

By default single client class with all REST operations is generated. This is convenient but often results in many name conflicts. So it is possible to organize operations using jaxrsNamespacing parameter. Options are:

  • singleObject means that one object with all operations will be generated (default)
  • perResource means that for each root resource one object will be generated
  • byAnnotation means that operations will be grouped by annotating root resources with annotation specified using jaxrsNamespacingAnnotation parameter.

Format of jaxrsNamespacingAnnotation parameter is <annotationClass>#<annotationElement> - for example io.swagger.annotations.Api#value. <annotationElement> can be omitted and defaults to value - for example io.swagger.annotations.Api.

Interface for JAX-RS application

Instead of (or in addition to) client class it is also possible to generate TypeScript interface for JAX-RS application. This can be turned on using generateJaxrsApplicationInterface configuration parameter.

While client implementation can only be generated in implementation file (.ts) interface can be generated also in declaration file (.d.ts).