Spring REST TypeScript Generator

Spring REST TypeScript Generator

In this TypeScript REST tutorial, we discuss a Spring REST TypeScript generator that creates models and services that reflect backend models and REST services. TypeScript generator that would be able to create models and services in TypeScript base upon REST interfaces.

I have been a backend developer for eighteen years without writing a single line of code on the client-side, but with the dawn of single-page applications, my cooperation with web developers got closer. I started to observe their work with interest. There are so many exciting possibilities on the frontend side. It made me consider to build up my technology stack and become a full stack developer.

I noticed that web developers create TypeScript models and services that reflect our backend model and REST services. It was a tedious job. What is more, after they finally mirrored what we had on the backend, it wasn't the end. Because we always have to keep in mind one thing that is very common in software development... CHANGE. Due to some new business requirements, backend services were modified. The change forced frontend developers to reanalyze backend services and refactor frontend applications so that they would match the server-side.

After some time, I have started my adventure with web development and came up with the idea that all this code could be generated based on type information in Java. I began to look for a TypeScript generator that would be able to create models and services in TypeScript base upon REST interfaces. As my research revealed, there were some libraries providing such functionality already, but none of them covered all our needs such as:

  • Support for JavaBean convention.
  • Support for FasterXML/Jackson annotation.
  • Support for Spring framework — the generation of TypeScript services that can call REST APIs developed in Spring.
  • Generated services aligned with Angular and ReactJS specific requirements (Observable or Promises API).

As a result, we decided to launch a small off-hours project that would provide the above functionality. It works, and we came up with the solution ready to use. It was tested and used in most of our commercial projects where web applications were based on Angular or React.

As our experienced showed, our library brought great benefits. The average generated code was on a level of 20% of web application codebase, but in terms of saved work on changes and tests, it was invaluable. Having such promising results, our company decided to make the project open source. If your development setup uses the Spring framework on the backend and Angular or React on the frontend side, you can experience the same benefits that we did. In this short article, I would like to introduce how you can REST with our spring-rest-2-ts TypeScript generator.

Examples

To get an idea of what spring-rest2ts generator can do, let's create a simple model and REST controller in Java, and we will show what will be generated in TypeScript

public class BaseDTO {
    private int id;
    @JsonFormat(shape = JsonFormat.Shape.NUMBER)
    private Date updateTimeStamp;
 }

public class OrderDTO extends BaseDTO {
    private double price;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
    private LocalDateTime orderTimestamp;
}

Spring REST controller:

@Controller
@RequestMapping("api/order")
public class OrderCtrl {

    @PostMapping(consumes = {"application/json"}, produces = {"application/json"})
    @ResponseBody
    @ResponseStatus(HttpStatus.CREATED)
    public OrderDTO createOrder(@RequestBody OrderDTO entity) {
        return entity;
    }

    @RequestMapping(path = "/{id}", method = RequestMethod.GET, produces = {"application/json"})
    @ResponseBody
    public OrderDTO getOrder(@PathVariable int id) {
        return new OrderDTO();
    }

}

In TypeScript, for DTO classes, we get two interfaces with mapped inheritance, where each field is mapped to their respective TypeScript types:

export interface Base {
    id: number;
    updateTimeStamp: number;
}

export interface Order extends Base {
    price: number;
    /**
     *    pattern : dd-MM-yyyy hh:mm:ss
     */
    orderTimestamp: string;
}

As we see, if a field has Jackson annotation, it is taken into account. If not, its transformation is based on Java types to TypeScript mapping. There is support for Type names mapping. In Java, we see that there is OrderDTO by providing proper name mapper which cuts off postfix DTO and we get type Order

Observable Based Service

The mapping of model classes is quite easy to understand. What's more interesting is the mapping of Spring REST controllers for which, in TypeScript, there is a generated implementation to call endpoints. Such an approach hides under method names, paths, and parameters, so the code will be resistant to changes on the backend. What is more important is that we transform return types to selected web frameworks; for Angular 2+ there is a generated valid Angular service ready to use for injection:

@Injectable()
export class OrderService {
    httpService: HttpClient;

    public constructor(httpService: HttpClient) {
        this.httpService = httpService;
    }

    public createOrder(entity: Order): Observable<Order> {
        let headers = new HttpHeaders().set('Content-type', 'application/json');
        return this.httpService.post<Order>('api/order', entity, {headers});
    }

    public getOrder(id: number): Observable<Order> {
        return this.httpService.get<Order>('api/order/' + id + '');
    }

}

OrderService is generated for OrderCtrl. Here, the type name was also transformed by the type name mapper. If the REST API is not available on the same host as the web application, there is a possibility to configure baseURL, which could be a path prefix o entire host reference

Promise Based Service

For web frameworks that are using the Promise API generator, proper configuration is also able to generate a service class:

export class OrderService {
    baseURL: URL;

    public constructor(baseURL: URL = new URL(window.document.URL)) {
        this.baseURL = baseURL;
    }

    public createOrder(entity: Order): Promise<Order> {
        const url = new URL('/api/order', this.baseURL);

        return fetch(url.toString(), {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify(entity)
        }).then(res => res.json());
    }

    public getOrder(id: number): Promise<Order> {
        const url = new URL('/api/order/' + id + '', this.baseURL);

        return fetch(url.toString(), {method: 'GET'}).then(res => res.json());
    }

}

Configuration

Due to the greater flexibility, TypeScript generator is configured by code; no configuration files are needed. This gives a possibility to easily extend generator in places where it is needed. Here is the simplest generator configurator:

    Rest2tsGenerator tsGenerator = new Rest2tsGenerator();

    // Java Classes filtering
    tsGenerator.setModelClassesCondition(new ExtendsJavaTypeFilter(BaseDTO.class));
    tsGenerator.setRestClassesCondition(new ExtendsJavaTypeFilter(BaseCtrl.class));

    // Java model classes converter setup
    JacksonObjectMapper jacksonObjectMapper = new JacksonObjectMapper();
    jacksonObjectMapper.setFieldsVisibility(JsonAutoDetect.Visibility.ANY);
    modelClassesConverter = new ModelClassesToTsInterfacesConverter(jacksonObjectMapper);
    modelClassesConverter.setClassNameMapper(new SubstringClassNameMapper("DTO", ""));
    tsGenerator.setModelClassesConverter(modelClassesConverter);

    // Spring REST controllers converter
    restClassesConverter = new SpringRestToTsConverter(new Angular4ImplementationGenerator());
    restClassesConverter.setClassNameMapper(new SubstringClassNameMapper("Ctrl", "Service"));
    tsGenerator.setRestClassesConverter(restClassesConverter);

    // set of java root packages for class scanning
    javaPackageSet = Collections.singleton("com.blueveery.springrest2ts.examples");
    tsGenerator.generate(javaPackageSet, Paths.get("../target/ts-code"));

For more information please check the project page on Github https://github.com/blue-veery-gmbh/spring-rest-2-ts.

TypeScript Spring REST webdev

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

How to Create REST with Spring-rest-2-ts and TypeScript

In this post, we discuss a Spring REST TypeScript generator that creates models and services that reflect backend models and REST services. I would like to introduce how you can REST with Spring-rest-2-ts TypeScript generator.

What is REST API? An Overview | Liquid Web

What is REST? The REST acronym is defined as a “REpresentational State Transfer” and is designed to take advantage of existing HTTP protocols when used

How to Create a Rest API with Java in Spring

We all know there are multiple ways to create a Rest API. You can use Flask, Django, Rails or Sinatra to do so, but this article will focus on creating said restful API endpoint using Java, Spring Boot and Spring Data Rest.

Spring Boot REST Validation Example | Spring Boot REST API Request Body Validation Example

Spring Boot REST Validation Example | Spring Boot REST API Request Body Validation Example

Spring Data REST Tutorial: Developing RESTful APIs with Ease

In this article, you will learn how to develop REST APIs with ease by using Spring Data REST and Spring Boot together. Throughout the article, you will scaffold a new Spring Boot application, create a JPA entity, and use Spring Data REST to provide some basic operations over it. Besides that, you will also learn how to validate the data your API is dealing with and how to secure the application.