leandreck / spring-typescript-services

Generate typescript services and type interfaces from spring annotated restcontrollers.
Apache License 2.0
29 stars 16 forks source link

Build Status Coverity Scan Build Status codecov Tech Debt Maven Status Known Vulnerabilities Codacy Badge license

Quality Gate

spring-typescript-services

Generate TypeScript interfaces and Angular services from Spring annotated @RestControllers. Get strongly typed interfaces for your Spring Boot microservices in no time.

Basic example

Spring @RestController:

@TypeScriptEndpoint
@RestController
@RequestMapping("/api/v1/customers")
public class CustomerController {

    @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public CustomerListDTO getAllCustomers() { ... }
}

Generated Angular service (TypeScript interfaces not shown here):

@Injectable()
export class CustomerController {

    private get serviceBaseURL(): string {
        return this.serviceConfig.context + '/api/v1/customers';
    }
    ...

    constructor(private httpClient: HttpClient, private serviceConfig: ServiceConfig) { }

    /* GET */
    public getAllCustomersGet(): Observable<CustomerListDTO> {
        const url = this.serviceBaseURL + '';
        const params = this.createHttpParams({});

        return this.httpClient.get<CustomerListDTO>(url, {params: params})
          .catch(error: HttpErrorResponse) => this.onError(error));
    }
    ...
}

Features

Currently not supported:

Getting started

Just specify the dependency in your Maven or Gradle based build and annotate a Spring @RestController with @TypeScriptEndpoint. Your next compile will then generate TypeScript files for every method with a @RequestMapping (or any shortcut annotation) producing "application/json" (MediaType.APPLICATION_JSON_VALUE).

Maven

<dependency>
    <groupId>org.leandreck.endpoints</groupId>
    <artifactId>annotations</artifactId>
    <version>0.4.0</version>
    <scope>provided</scope> <!-- the annotations and processor are only needed at compile time -->
    <optional>true</optional> <!-- they need not to be transitively included in dependent artifacts -->
</dependency>
<!-- * because of spring-boot dependency handling they nevertheless get included in fat jars -->

If you are using the maven-compiler-plugin, add spring-typescript-services to annotationProcesserPaths within the plugin configuration:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    ...
    <configuration>
        <annotationProcessorPaths>
            <path>
                <groupId>org.leandreck.endpoints</groupId>
                <artifactId>annotations</artifactId>
                <version>0.4.0</version>
            </path>
            ...
        </annotationProcessorPaths>
        ...
    </configuration>
</plugin>

Gradle

compileOnly 'org.leandreck.endpoints:annotations:0.4.0'

Usage

If supported Spring @RestContollers were found, you will find the generated TypeScript files under ./target/generated-sources/.

All services are part of an Angular module called APIModule, which you only need to import within your own module. Currently you also need to manually include HttpClientModule from @angular/common/http:

@NgModule({
  ...
  imports: [
    ...
    APIModule.forRoot(),
    HttpClientModule
  ],
  ...
})
export class AppModule { }

See API for configuration options.

Known Issues

API

Spring Boot Annotations

@TypeScriptEndpoint

Annotate your @RestController to generate a corresponding Angular service and interface files.

By default the Angular services will have the same name as the @RestController. You can overwrite this by specifying a custom name:

@TypeScriptEndpoint(value = "FooService")
public class FooController { }

You can provide your own <#FREEMARKER>-template to use for generating TypeScript files for this specific TypeScriptEndpoint. This overwrites any defaults. The default template is located at /org/leandreck/endpoints/templates/typescript/service.ftl.

@TypeScriptEndpoint(template = "/org/leandreck/endpoints/templates/typescript/custom.ftl")
public class FooController { }

@TypeScriptTemplatesConfiguration

Configure if and what method suffixes are used in the default templates or provide your own.

Disable suffixes:

@TypeScriptTemplatesConfiguration(useSuffixes = false)
public class FooController { }

Modify suffix based on HTTP method (e.g. replace suffixGet by suffixPost):

@TypeScriptTemplatesConfiguration(suffixGet = "GET")
public class FooController { }

Modify the TypeScript output by providing your own <#FREEMARKER>-templates. Have a look at the default ones org.leandreck.enpoints.templates.typescript.

@TypeScriptTemplatesConfiguration(apimodule = "/org/leandreck/endpoints/templates/typescript/custom.ftl")
public class FooController { }

Available options:

@TypeScriptIgnore

Methods or fields annotated with @TypeScriptIgnore will be ignored by the annotation processor.

Annotate methods in your @RestController if you do not want to include them in the generated Angular service. If applied to a field it is not included in the respective interface file.

@TypeScriptType

Annotate Fields with @TypeScriptType to specify a custom template or override default mappings.

@TypeScriptType("any")
private Foobar foo;

will result in

foo: any

Angular Module

APIModule.forRoot()

The APIModule optionally receives a ServiceConfig which you may use to further configure the generated services.

Modify your endpoint's base URL path:

APIModule.forRoot({ context: 'http://www.example.com/path/to/api' })

Enable debugging to get some console output:

APIModule.forRoot({ debug: true })

Provide your own error handler function:

APIModule.forRoot({ onError: (error) => Observable.throw('An API error occured:' + error.message) })

How does it work?

spring-typescript-services is a Java annotation processor to generate Angular services and TypeScript types to access your spring @RestControllers.

It generates a service.ts file for every with @TypeScriptEndpoint annotated class and includes functions for every enclosed public Java Method with a @RequestMapping producing JSON. The TypeScript files are generated by populating <#FREEMARKER>-template files. You can specify your own template files or use the bundled defaults.