Swagger autogen - overwriting implementation code

2019-09-19 23:40发布

问题:

Does anyone here have a good strategy for dealing with a changing API spec?

API change -> regenerate code -> implement changes.

I'm thinking generating Java interfaces and having separate class files which implement these interfaces. Any interface mismatches will show up in IDE (e.g. IntelliJ)

Right now if I do the implementation, the files where I wrote the implementation gets overwritten...

回答1:

My generated swagger Code will be put under src/gen/Java. Everytime i generate the whole folder will be deleted. That way the implementation of the interfaces will not be overwritten. Also i do not commit the gen folder.

EDIT

To illustrate it a little bit more have a look at the templates: https://github.com/Mehtrick/swagger-templates

The important ones are the api and apicontroller.mustache

The generated controller classes look like this

@RestController
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)
public class UsersApiController {

    @Autowired
    private UsersApi UsersApiService;

    @PreAuthorize("isAuthenticated()  and hasAuthority('USER')")
    @RequestMapping(value = "/users/current", produces = { "application/json" }, method = RequestMethod.GET)
    public ResponseEntity<User> getCurrentUser() throws Exception {
        return UsersApiService.getCurrentUser();
    }

    @RequestMapping(value = "/users", produces = { "application/json" }, method = RequestMethod.POST)
    public ResponseEntity<Void> registerUser(

            @Valid @RequestBody User body

    ) throws Exception {
        return UsersApiService.registerUser(body);
    }

}

And then the generated UsersApi looks like this:

public interface UsersApi {

    /**
     * Loads the current user
     */
    ResponseEntity<User> getCurrentUser() throws Exception;

    /**
     * Registers a new user
     */
    ResponseEntity<Void> registerUser(@Valid @RequestBody User body) throws Exception;

}

All I have to do is to implement the generated api interfaces as spring components.

These classes are generated from Swagger with this gradle plugin:

https://github.com/int128/gradle-swagger-generator-plugin

The build config looks like this:

ext {
    swaggeryaml = file("${projectDir}/swagger/swagger.yaml")
}

apply plugin: "org.hidetake.swagger.generator"

validateSwagger {
  inputFile = swaggeryaml
}


generateSwaggerCode {
  language = 'spring'
  inputFile = swaggeryaml
  components = ['models','apis']
  configFile = file("${swaggerconfigpath}")
  templateDir = file("${projectDir}/swagger/templates")
}

In this example the normal spring-swagger-codegen is used but with my customized templates under ${projectDir}/swagger/templates

The buildscript is configured to move the generated files to src/gen/java and before that it deletes the whole src/gen/java folder

task cleanSwagger(type: Delete){
  delete "${projectDir}/src/gen/java/"
}

task moveSwagger(type: Copy){
  dependsOn "generateSwaggerCode"
  from "${buildDir}/swagger-code/src/main/java"
  into "${projectDir}/src/gen/java"
}

The build tasks are called when:

  • the java code compiles (like on a ci-server)
  • The IDE classpath (in my case Eclipse) is initialized

compileJava.dependsOn swaggerGen

Hope this helps