armeria icon indicating copy to clipboard operation
armeria copied to clipboard

Add api generator using OAS file#1951

Open moonchanyong opened this issue 6 years ago • 17 comments

Motivation:

  • #1951
  • To generate server code from OAS doc

Modification:

  • add cli made by native-image

Result:

Pre-step If you don't install graalvm and native-image use this image mcy7272/native-image:latest that made on grallvm official image for install native-image

  1. Run gradle task shadow jar // this will make a jar named api-generator-0.95.1-SNAPSHOT-all.jar
  2. Run below command
native-image -H:EnableURLProtocols=https,http --report-unsupported-elements-at-runtime --no-fallback -H:+ReportExceptionStackTraces --no-server -jar api-generator-0.95.1-SNAPSHOT-all.jar api-gen
  1. Run ./api-gen <oas-doc-path> <output-dir-path>

moonchanyong avatar Nov 10 '19 12:11 moonchanyong

Codecov Report

:white_check_mark: All modified and coverable lines are covered by tests. :white_check_mark: Project coverage is 74.65%. Comparing base (8d0de0f) to head (3c8a4b2). :warning: Report is 2767 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #2245      +/-   ##
============================================
+ Coverage     73.64%   74.65%   +1.01%     
- Complexity     9625    19413    +9788     
============================================
  Files           840     1411     +571     
  Lines         37041    73829   +36788     
  Branches       4566     9819    +5253     
============================================
+ Hits          27277    55120   +27843     
- Misses         7438    14244    +6806     
- Partials       2326     4465    +2139     

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

codecov[bot] avatar Nov 10 '19 12:11 codecov[bot]

Thanks for helping with this! Wondering, have you thought about implementing swagger's codegen interface instead of creating a separate CLI?

https://github.com/swagger-api/swagger-codegen/blob/master/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SpringCodegen.java

If we use the standard interfaces, we can take advantage of existing tooling in the ecosystem - for example I found this one

https://github.com/int128/gradle-swagger-generator-plugin/blob/master/README.md#use-custom-generator-class

I think even if we publish a separate jar with our implementation most existing tooling will still work well with it.

anuraaga avatar Nov 11 '19 04:11 anuraaga

@anuraaga That's a great point. What do you think, @moonchanyong ?

trustin avatar Nov 11 '19 07:11 trustin

@anuraaga Your opinion is reasonable. so I think if armeria-codegen imaplementing swagger's codegen interface can be added to swagger-codegen, we can add just how to use swagger-codegen at this repo. I will try to ask whether armeria-codegen can be added.

moonchanyong avatar Nov 11 '19 09:11 moonchanyong

@moonchanyong Sure. If they are not interested, we can still add it in this repository, so no worries.

trustin avatar Nov 11 '19 09:11 trustin

Any updates on this, @moonchanyong ?

trustin avatar Dec 12 '19 10:12 trustin

Any updates on this, @moonchanyong ?

Sorry for waiting. I go on progress. but not have satisfactory results yet.

below link is code to be generated code by current work. https://github.com/moonchanyong/example

moonchanyong avatar Dec 12 '19 12:12 moonchanyong

Can I receive feedback about generated code? below tree Indicates generated files. and I used to generate petstore.yaml .

project
│   build.gradle   
│   petstore.yaml  
│
└───src.main.java.example.armeria.server 
│   │   Main.java
│   │
│   └───annotated
│       │   PetApi.java
│       │   StoreApi.java
│       │   UserApi.java
│   └───model   
│       │   Amount.java
│       │   Category.java
│       │   ModelApiResponse.java
│       │   Order.java
│       │   Pet.java
│       │   Tag.java
│       │   User.java

and I have registered an issue at swagger-codegen

moonchanyong avatar Dec 14 '19 10:12 moonchanyong

@moonchanyong Awesome! Let me take a look soon.

trustin avatar Dec 14 '19 14:12 trustin

@moonchanyong Had a quick look. Looking nice!

  • Can we use primitive types for non-null numbers? e.g. long petId vs @NotNull Long petId
  • @Produces("application/json") or Consumes("application/json") could be @ProducesJson or @ConsumesJson.
    • Similarly, we could add @ProducesXml and @ConsumesXml to Armeria.
  • Question: Would it be better using HttpRequest for multipart uploads instead of byte[]?
  • Question: Did you implement model-generating part? If so, would it be better generating immutable model classes with an all-args constructor?

trustin avatar Dec 16 '19 09:12 trustin

  • Can we use primitive types for non-null numbers? e.g. long petId vs @NotNull Long petId

yes, but the default-generator sets path parameter to be required value. I think it is the right way, may there is any other case when path parameter is not required?

  • @Produces("application/json") or Consumes("application/json") could be @ProducesJson or @ConsumesJson.

    • Similarly, we could add @ProducesXml and @ConsumesXml to Armeria.

ok. I add short Annotation if it exists.

  • Question: Would it be better using HttpRequest for multipart uploads instead of byte[]?

ok. I have modified

  • Question: Did you implement model-generating part? If so, would it be better generating immutable model classes with an all-args constructor?

as I understand, I remove all setter and JacksonRequestConverterFunction work with having partial properties when a constructor is default. may there be other things to do?

newly generated

moonchanyong avatar Dec 28 '19 10:12 moonchanyong

as I understand, I remove all setter and JacksonRequestConverterFunction work with having partial properties when a constructor is default. may there be other things to do?

You could create an all-args constructor annotated with @JsonCreator and then make optional properties nullable?

trustin avatar Dec 30 '19 01:12 trustin

Found a few more issues:

  • name and status in PetApi.updatePetWithForm() were not annotated with @Param
  • PetApi.uploadFile() has an incorrect response type in the comment block:
          /*
           *  TODO: Implement `uploadFile` method
           *  Response Type: ModelApiResponse
           */
          return HttpResponse.of(HttpStatus.OK);
    

trustin avatar Dec 30 '19 01:12 trustin

yes, but the default-generator sets path parameter to be required value. I think it is the right way, may there is any other case when path parameter is not required?

What I'm saying is that we can simplify @NotNull Long to just long because path parameter always exists and thus it's always non-null.

trustin avatar Dec 30 '19 01:12 trustin

@moonchanyong Why was this closed?

trustin avatar Nov 16 '20 00:11 trustin

@trustin oh... I have got misunderstanding the comment of #2402. I will continue to try this issue. sorry for the late.

moonchanyong avatar Nov 18 '20 02:11 moonchanyong

No worries, @moonchanyong. We really look forward to this feature 🙏 🙇

trustin avatar Nov 18 '20 12:11 trustin