forked from loafle/openapi-generator-original
Merge remote-tracking branch 'origin/4.2.x' into 5.0.x
This commit is contained in:
commit
1c31dce4bd
4
.gitignore
vendored
4
.gitignore
vendored
@ -232,3 +232,7 @@ samples/client/petstore/elm/index.html
|
||||
# C
|
||||
samples/client/petstore/c/build
|
||||
samples/client/petstore/c/*.so
|
||||
|
||||
# Ruby
|
||||
samples/openapi3/client/petstore/ruby/Gemfile.lock
|
||||
samples/openapi3/client/petstore/ruby-faraday/Gemfile.lock
|
||||
|
@ -94,6 +94,12 @@ before_install:
|
||||
# - Rely on `kerl` for [pre-compiled versions available](https://docs.travis-ci.com/user/languages/erlang#Choosing-OTP-releases-to-test-against). Rely on installation path chosen by [`travis-erlang-builder`](https://github.com/travis-ci/travis-erlang-builder/blob/e6d016b1a91ca7ecac5a5a46395bde917ea13d36/bin/compile#L18).
|
||||
# - . ~/otp/18.2.1/activate && erl -version
|
||||
#- curl -f -L -o ./rebar3 https://s3.amazonaws.com/rebar3/rebar3 && chmod +x ./rebar3 && ./rebar3 version && export PATH="${TRAVIS_BUILD_DIR}:$PATH"
|
||||
# install Qt 5.10
|
||||
- sudo add-apt-repository --yes ppa:beineri/opt-qt-5.10.1-trusty
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install qt510-meta-minimal
|
||||
- source /opt/qt510/bin/qt510-env.sh
|
||||
- qmake -v
|
||||
|
||||
# show host table to confirm petstore.swagger.io is mapped to localhost
|
||||
- cat /etc/hosts
|
||||
|
@ -2,8 +2,19 @@ kind: pipeline
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: test
|
||||
# test Java 11 HTTP client
|
||||
- name: java11-test
|
||||
image: hirokimatsumoto/alpine-openjdk-11
|
||||
commands:
|
||||
- ./mvnw clean install
|
||||
- ./mvnw --quiet verify -Psamples.droneio
|
||||
# test ocaml petstore client
|
||||
- name: ocaml-test
|
||||
image: ocaml/opam2:4.07
|
||||
commands:
|
||||
- sudo apt-get -y install m4
|
||||
- cd samples/client/petstore/ocaml
|
||||
- opam install ppx_deriving_yojson cohttp ppx_deriving cohttp-lwt-unix
|
||||
- eval $(opam env)
|
||||
- sudo chmod -R 777 .
|
||||
- dune build --build-dir=./_build
|
||||
|
@ -10,6 +10,7 @@ import java.util.TimeZone;
|
||||
|
||||
import org.junit.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
|
||||
|
||||
public class ApiClientTest {
|
||||
@ -329,24 +330,18 @@ public class ApiClientTest {
|
||||
assertEquals("sun.gif", apiClient.sanitizeFilename(".\\sun.gif"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testInterceptorCleanupWithNewClient() {
|
||||
public void testNewHttpClient() {
|
||||
OkHttpClient oldClient = apiClient.getHttpClient();
|
||||
assertEquals(1, oldClient.networkInterceptors().size());
|
||||
|
||||
OkHttpClient newClient = new OkHttpClient();
|
||||
apiClient.setHttpClient(newClient);
|
||||
assertEquals(1, apiClient.getHttpClient().networkInterceptors().size());
|
||||
apiClient.setHttpClient(newClient);
|
||||
assertEquals(1, apiClient.getHttpClient().networkInterceptors().size());
|
||||
apiClient.setHttpClient(oldClient.newBuilder().build());
|
||||
assertThat(apiClient.getHttpClient(), is(not(oldClient)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterceptorCleanupWithSameClient() {
|
||||
OkHttpClient oldClient = apiClient.getHttpClient();
|
||||
assertEquals(1, oldClient.networkInterceptors().size());
|
||||
apiClient.setHttpClient(oldClient);
|
||||
assertEquals(1, apiClient.getHttpClient().networkInterceptors().size());
|
||||
/**
|
||||
* Tests the invariant that the HttpClient for the ApiClient must never be null
|
||||
*/
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void testNullHttpClient() {
|
||||
apiClient.setHttpClient(null);
|
||||
}
|
||||
}
|
||||
|
30
README.md
30
README.md
@ -17,7 +17,7 @@
|
||||
|
||||
<div align="center">
|
||||
|
||||
[](https://gitter.im/OpenAPITools/openapi-generator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://join.slack.com/t/openapi-generator/shared_invite/enQtNzAyNDMyOTU0OTE1LTY5ZDBiNDI5NzI5ZjQ1Y2E5OWVjMjZkYzY1ZGM2MWQ4YWFjMzcyNDY5MGI4NjQxNDBiMTlmZTc5NjY2ZTQ5MGM)
|
||||
[](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.openapitools%22%20AND%20a%3A%22openapi-generator%22)
|
||||
[](https://twitter.com/oas_generator)
|
||||
|
||||
@ -59,7 +59,7 @@ OpenAPI Generator allows generation of API client libraries (SDK generation), se
|
||||
|
||||
| | Languages/Frameworks |
|
||||
|-|-|
|
||||
**API clients** | **ActionScript**, **Ada**, **Apex**, **Bash**, **C**, **C#** (.net 2.0, 3.5 or later), **C++** (cpp-restsdk, Qt5, Tizen), **Clojure**, **Dart (1.x, 2.x)**, **Elixir**, **Elm**, **Eiffel**, **Erlang**, **Go**, **Groovy**, **Haskell** (http-client, Servant), **Java** (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured, Spring 5 Web Client), **Kotlin**, **Lua**, **Node.js/JavaScript** (ES5, ES6, AngularJS with Google Closure Compiler annotations, Flow types) **Objective-C**, **Perl**, **PHP**, **PowerShell**, **Python**, **R**, **Ruby**, **Rust** (rust, rust-server), **Scala** (akka, http4s, scalaz, swagger-async-httpclient), **Swift** (2.x, 3.x, 4.x), **Typescript** (AngularJS, Angular (2.x - 7.x), Aurelia, Axios, Fetch, Inversify, jQuery, Node, Rxjs)
|
||||
**API clients** | **ActionScript**, **Ada**, **Apex**, **Bash**, **C**, **C#** (.net 2.0, 3.5 or later), **C++** (cpp-restsdk, Qt5, Tizen), **Clojure**, **Dart (1.x, 2.x)**, **Elixir**, **Elm**, **Eiffel**, **Erlang**, **Go**, **Groovy**, **Haskell** (http-client, Servant), **Java** (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured, Spring 5 Web Client), **Kotlin**, **Lua**, **Node.js/JavaScript** (ES5, ES6, AngularJS with Google Closure Compiler annotations, Flow types), **Objective-C**, **OCaml**, **Perl**, **PHP**, **PowerShell**, **Python**, **R**, **Ruby**, **Rust** (rust, rust-server), **Scala** (akka, http4s, scalaz, swagger-async-httpclient), **Swift** (2.x, 3.x, 4.x), **Typescript** (AngularJS, Angular (2.x - 7.x), Aurelia, Axios, Fetch, Inversify, jQuery, Node, Rxjs)
|
||||
**Server stubs** | **Ada**, **C#** (ASP.NET Core, NancyFx), **C++** (Pistache, Restbed, Qt5 QHTTPEngine), **Erlang**, **F#** (Giraffe), **Go** (net/http, Gin), **Haskell** (Servant), **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, RestEasy, Play Framework, [PKMST](https://github.com/ProKarma-Inc/pkmst-getting-started-examples)), **Kotlin** (Spring Boot, Ktor), **PHP** (Laravel, Lumen, Slim, Silex, [Symfony](https://symfony.com/), [Zend Expressive](https://github.com/zendframework/zend-expressive)), **Python** (Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Rust** (rust-server), **Scala** ([Finch](https://github.com/finagle/finch), [Lagom](https://github.com/lagom/lagom), [Play](https://www.playframework.com/), Scalatra)
|
||||
**API documentation generators** | **HTML**, **Confluence Wiki**
|
||||
**Configuration files** | [**Apache2**](https://httpd.apache.org/)
|
||||
@ -101,8 +101,9 @@ The OpenAPI Specification has undergone 3 revisions since initial creation in 20
|
||||
OpenAPI Generator Version | Release Date | Notes
|
||||
---------------------------- | ------------ | -----
|
||||
5.0.0 (upcoming major release) [SNAPSHOT](https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/5.0.0-SNAPSHOT/)| 13.05.2020 | Major release with breaking changes (no fallback)
|
||||
4.1.0 (upcoming minor release) [SNAPSHOT](https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/4.1.0-SNAPSHOT/)| 31.07.2019 | Minor release (breaking changes with fallbacks)
|
||||
[4.0.3](https://github.com/OpenAPITools/openapi-generator/releases/tag/v4.0.3) (latest stable release) | 09.07.2019 | Patch release (bug fixes, minor enhancements, etc)
|
||||
4.2.0 (upcoming minor release) [SNAPSHOT](https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/4.2.0-SNAPSHOT/)| 09.10.2019 | Minor release (breaking changes with fallbacks)
|
||||
4.1.1 (upcoming minor release) [SNAPSHOT](https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/4.1.1-SNAPSHOT/)| 23.08.2019 | Patch release (bug fixes, enhancements)
|
||||
[4.1.0](https://github.com/OpenAPITools/openapi-generator/releases/tag/v4.1.0) (latest stable release) | 09.08.2019 | Minor release (breaking changes with fallbacks)
|
||||
|
||||
OpenAPI Spec compatibility: 1.0, 1.1, 1.2, 2.0, 3.0
|
||||
|
||||
@ -158,16 +159,16 @@ See the different versions of the [openapi-generator-cli](https://mvnrepository.
|
||||
<!-- RELEASE_VERSION -->
|
||||
If you're looking for the latest stable version, you can grab it directly from Maven.org (Java 8 runtime at a minimum):
|
||||
|
||||
JAR location: `http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.0.3/openapi-generator-cli-4.0.3.jar`
|
||||
JAR location: `http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.1.0/openapi-generator-cli-4.1.0.jar`
|
||||
|
||||
For **Mac/Linux** users:
|
||||
```sh
|
||||
wget http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.0.3/openapi-generator-cli-4.0.3.jar -O openapi-generator-cli.jar
|
||||
wget http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.1.0/openapi-generator-cli-4.1.0.jar -O openapi-generator-cli.jar
|
||||
```
|
||||
|
||||
For **Windows** users, you will need to install [wget](http://gnuwin32.sourceforge.net/packages/wget.htm) or you can use Invoke-WebRequest in PowerShell (3.0+), e.g.
|
||||
```
|
||||
Invoke-WebRequest -OutFile openapi-generator-cli.jar http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.0.3/openapi-generator-cli-4.0.3.jar
|
||||
Invoke-WebRequest -OutFile openapi-generator-cli.jar http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.1.0/openapi-generator-cli-4.1.0.jar
|
||||
```
|
||||
|
||||
After downloading the JAR, run `java -jar openapi-generator-cli.jar help` to show the usage.
|
||||
@ -382,10 +383,10 @@ openapi-generator version
|
||||
```
|
||||
|
||||
<!-- RELEASE_VERSION -->
|
||||
Or install a particular OpenAPI Generator version (e.g. v4.0.3):
|
||||
Or install a particular OpenAPI Generator version (e.g. v4.1.0):
|
||||
|
||||
```sh
|
||||
npm install @openapitools/openapi-generator-cli@cli-4.0.3 -g
|
||||
npm install @openapitools/openapi-generator-cli@cli-4.1.0 -g
|
||||
```
|
||||
|
||||
Or install it as dev-dependency:
|
||||
@ -409,7 +410,7 @@ java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generat
|
||||
(if you're on Windows, replace the last command with `java -jar modules\openapi-generator-cli\target\openapi-generator-cli.jar generate -i https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g php -o c:\temp\php_api_client`)
|
||||
|
||||
<!-- RELEASE_VERSION -->
|
||||
You can also download the JAR (latest release) directly from [maven.org](http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.0.3/openapi-generator-cli-4.0.3.jar)
|
||||
You can also download the JAR (latest release) directly from [maven.org](http://central.maven.org/maven2/org/openapitools/openapi-generator-cli/4.1.0/openapi-generator-cli-4.1.0.jar)
|
||||
<!-- /RELEASE_VERSION -->
|
||||
|
||||
To get a list of **general** options available, please run `java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar help generate`
|
||||
@ -550,6 +551,7 @@ Here are some companies/projects (alphabetical order) using OpenAPI Generator in
|
||||
- [CAM](https://www.cam-inc.co.jp/)
|
||||
- [Camptocamp](https://www.camptocamp.com/en)
|
||||
- [codecentric AG](https://www.codecentric.de/)
|
||||
- [Commencis](https://www.commencis.com/)
|
||||
- [Cupix](https://www.cupix.com/)
|
||||
- [DB Systel](https://www.dbsystel.de)
|
||||
- [FormAPI](https://formapi.io/)
|
||||
@ -594,6 +596,7 @@ Here are some companies/projects (alphabetical order) using OpenAPI Generator in
|
||||
- 2018/12/09 - [openapi-generator をカスタマイズする方法](https://qiita.com/watiko/items/0961287c02eac9211572) by [@watiko](https://qiita.com/watiko)
|
||||
- 2019/01/03 - [Calling a Swagger service from Apex using openapi-generator](https://lekkimworld.com/2019/01/03/calling-a-swagger-service-from-apex-using-openapi-generator/) by [Mikkel Flindt Heisterberg](https://lekkimworld.com)
|
||||
- 2019/01/13 - [OpenAPI GeneratorでRESTful APIの定義書から色々自動生成する](https://ky-yk-d.hatenablog.com/entry/2019/01/13/234108) by [@ky_yk_d](https://twitter.com/ky_yk_d)
|
||||
- 2019/01/20 - [Contract-First API Development with OpenAPI Generator and Connexion](https://medium.com/commencis/contract-first-api-development-with-openapi-generator-and-connexion-b21bbf2f9244) by [Anil Can Aydin](https://github.com/anlcnydn)
|
||||
- 2019/01/30 - [Rapid Application Development With API First Approach Using Open-API Generator](https://dzone.com/articles/rapid-api-development-using-open-api-generator) by [Milan Sonkar](https://dzone.com/users/828329/milan_sonkar.html)
|
||||
- 2019/02/02 - [平静を保ち、コードを生成せよ 〜 OpenAPI Generator誕生の背景と軌跡 〜](https://speakerdeck.com/akihito_nakano/gunmaweb34) by [中野暁人](https://github.com/ackintosh) at [Gunma.web #34 スキーマ駆動開発](https://gunmaweb.connpass.com/event/113974/)
|
||||
- 2019/02/20 - [An adventure in OpenAPI V3 code generation](https://mux.com/blog/an-adventure-in-openapi-v3-api-code-generation/) by [Phil Cluff](https://mux.com/blog/author/philc/)
|
||||
@ -673,16 +676,19 @@ Here is a list of template creators:
|
||||
* Java (Vertx): @lopesmcc
|
||||
* Java (Google APIs Client Library): @charlescapps
|
||||
* Java (Rest-assured): @viclovsky
|
||||
* Java (Java 11 Native HTTP client): @bbdouglas
|
||||
* Javascript/NodeJS: @jfiala
|
||||
* Javascript (Closure-annotated Angular) @achew22
|
||||
* Javascript (Flow types) @jaypea
|
||||
* JMeter: @davidkiss
|
||||
* Kotlin: @jimschubert [:heart:](https://www.patreon.com/jimschubert)
|
||||
* Lua: @daurnimator
|
||||
* OCaml: @cgensoul
|
||||
* Perl: @wing328 [:heart:](https://www.patreon.com/wing328)
|
||||
* PHP (Guzzle): @baartosz
|
||||
* PowerShell: @beatcracker
|
||||
* R: @ramnov
|
||||
* Ruby (Faraday): @meganemura @dkliban
|
||||
* Rust: @farcaller
|
||||
* Rust (rust-server): @metaswitch
|
||||
* Scala (scalaz & http4s): @tbrown1979
|
||||
@ -725,6 +731,7 @@ Here is a list of template creators:
|
||||
* JAX-RS RestEasy (JBoss EAP): @jfiala
|
||||
* Kotlin: @jimschubert [:heart:](https://www.patreon.com/jimschubert)
|
||||
* Kotlin (Spring Boot): @dr4ke616
|
||||
* NodeJS Express: @YishTish
|
||||
* PHP Laravel: @renepardon
|
||||
* PHP Lumen: @abcsun
|
||||
* PHP Slim: @jfastnacht
|
||||
@ -802,13 +809,14 @@ If you want to join the committee, please kindly apply by sending an email to te
|
||||
| Lua | @daurnimator (2017/08) |
|
||||
| NodeJS/Javascript | @CodeNinjai (2017/07) @frol (2017/07) @cliffano (2017/07) |
|
||||
| ObjC | |
|
||||
| OCaml | @cgensoul (2019/08) |
|
||||
| Perl | @wing328 (2017/07) [:heart:](https://www.patreon.com/wing328) @yue9944882 (2019/06) |
|
||||
| PHP | @jebentier (2017/07), @dkarlovi (2017/07), @mandrean (2017/08), @jfastnacht (2017/09), @ackintosh (2017/09) [:heart:](https://www.patreon.com/ackintosh/overview), @ybelenko (2018/07), @renepardon (2018/12) |
|
||||
| PowerShell | |
|
||||
| Python | @taxpon (2017/07) @frol (2017/07) @mbohlool (2017/07) @cbornet (2017/09) @kenjones-cisco (2017/11) @tomplus (2018/10) @Jyhess (2019/01) |
|
||||
| R | @Ramanth (2019/07) @saigiridhar21 (2019/07) |
|
||||
| Ruby | @cliffano (2017/07) @zlx (2017/09) @autopp (2019/02) |
|
||||
| Rust | @frol (2017/07) @farcaller (2017/08) @bjgill (2017/12) |
|
||||
| Rust | @frol (2017/07) @farcaller (2017/08) @bjgill (2017/12) @richardwhiuk (2019/07) |
|
||||
| Scala | @clasnake (2017/07), @jimschubert (2017/09) [:heart:](https://www.patreon.com/jimschubert), @shijinkui (2018/01), @ramzimaalej (2018/03) |
|
||||
| Swift | @jgavris (2017/07) @ehyche (2017/08) @Edubits (2017/09) @jaz-ah (2017/09) @d-date (2018/03) |
|
||||
| TypeScript | @TiFu (2017/07) @taxpon (2017/07) @sebastianhaas (2017/07) @kenisteward (2017/07) @Vrolijkx (2017/09) @macjohnny (2018/01) @nicokoenig (2018/09) @topce (2018/10) @akehir (2019/07) |
|
||||
|
32
bin/nodejs-express-petstore-server.sh
Executable file
32
bin/nodejs-express-petstore-server.sh
Executable file
@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
SCRIPT="$0"
|
||||
echo "# START SCRIPT: $SCRIPT"
|
||||
|
||||
while [ -h "$SCRIPT" ] ; do
|
||||
ls=`ls -ld "$SCRIPT"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
SCRIPT="$link"
|
||||
else
|
||||
SCRIPT=`dirname "$SCRIPT"`/"$link"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -d "${APP_DIR}" ]; then
|
||||
APP_DIR=`dirname "$SCRIPT"`/..
|
||||
APP_DIR=`cd "${APP_DIR}"; pwd`
|
||||
fi
|
||||
|
||||
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
|
||||
|
||||
if [ ! -f "$executable" ]
|
||||
then
|
||||
mvn -B clean package
|
||||
fi
|
||||
|
||||
# if you've executed sbt assembly previously it will use that instead.
|
||||
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
|
||||
ags="generate -t modules/openapi-generator/src/main/resources/nodejs-express-server -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g nodejs-express-server -o samples/server/petstore/nodejs-express-server -Dservice $@"
|
||||
|
||||
java $JAVA_OPTS -jar $executable $ags
|
34
bin/ocaml-petstore.sh
Executable file
34
bin/ocaml-petstore.sh
Executable file
@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
|
||||
SCRIPT="$0"
|
||||
echo "# START SCRIPT: $SCRIPT"
|
||||
|
||||
while [ -h "$SCRIPT" ] ; do
|
||||
ls=`ls -ld "$SCRIPT"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
SCRIPT="$link"
|
||||
else
|
||||
SCRIPT=`dirname "$SCRIPT"`/"$link"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -d "${APP_DIR}" ]; then
|
||||
APP_DIR=`dirname "$SCRIPT"`/..
|
||||
APP_DIR=`cd "${APP_DIR}"; pwd`
|
||||
fi
|
||||
|
||||
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
|
||||
|
||||
if [ ! -f "$executable" ]
|
||||
then
|
||||
mvn -B clean package
|
||||
fi
|
||||
|
||||
# if you've executed sbt assembly previously it will use that instead.
|
||||
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
|
||||
|
||||
args="generate -t modules/openapi-generator/src/main/resources/ocaml -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g ocaml -o samples/client/petstore/ocaml --additional-properties packageName=petstore_client $@"
|
||||
|
||||
echo "java ${JAVA_OPTS} -jar ${executable} ${args}"
|
||||
java $JAVA_OPTS -jar $executable $args
|
34
bin/openapi3/ocaml-client-petstore.sh
Executable file
34
bin/openapi3/ocaml-client-petstore.sh
Executable file
@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
|
||||
SCRIPT="$0"
|
||||
echo "# START SCRIPT: $SCRIPT"
|
||||
|
||||
while [ -h "$SCRIPT" ] ; do
|
||||
ls=`ls -ld "$SCRIPT"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
SCRIPT="$link"
|
||||
else
|
||||
SCRIPT=`dirname "$SCRIPT"`/"$link"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -d "${APP_DIR}" ]; then
|
||||
APP_DIR=`dirname "$SCRIPT"`/..
|
||||
APP_DIR=`cd "${APP_DIR}"; pwd`
|
||||
fi
|
||||
|
||||
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
|
||||
|
||||
if [ ! -f "$executable" ]
|
||||
then
|
||||
mvn -B clean package
|
||||
fi
|
||||
|
||||
# if you've executed sbt assembly previously it will use that instead.
|
||||
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DdebugOperations -DloggerPath=conf/log4j.properties"
|
||||
|
||||
args="generate -t modules/openapi-generator/src/main/resources/ocaml -i modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml -g ocaml -o samples/openapi3/client/petstore/ocaml/ --additional-properties packageName=petstore_client $@"
|
||||
|
||||
echo "java ${JAVA_OPTS} -jar ${executable} ${args}"
|
||||
java $JAVA_OPTS -jar $executable $args
|
@ -23,7 +23,7 @@ if [ ! -d "${APP_DIR}" ]; then
|
||||
fi
|
||||
|
||||
# Make sure that we are regenerating the sample by removing any existing target directory
|
||||
TARGET_DIR="$SCRIPT_DIR/../../samples/server/petstore/php-symfony/SymfonyBundle-php"
|
||||
TARGET_DIR="$SCRIPT_DIR/../../samples/openapi3/server/petstore/php-symfony/SymfonyBundle-php"
|
||||
if [ -d "$TARGET_DIR" ]; then
|
||||
rm -rf $TARGET_DIR
|
||||
fi
|
||||
|
43
bin/openapi3/ruby-client-faraday-petstore.sh
Executable file
43
bin/openapi3/ruby-client-faraday-petstore.sh
Executable file
@ -0,0 +1,43 @@
|
||||
#!/bin/sh
|
||||
|
||||
SCRIPT="$0"
|
||||
echo "# START SCRIPT: $SCRIPT"
|
||||
|
||||
while [ -h "$SCRIPT" ] ; do
|
||||
ls=`ls -ld "$SCRIPT"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
SCRIPT="$link"
|
||||
else
|
||||
SCRIPT=`dirname "$SCRIPT"`/"$link"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -d "${APP_DIR}" ]; then
|
||||
APP_DIR=`dirname "$SCRIPT"`/..
|
||||
APP_DIR=`cd "${APP_DIR}"; pwd`
|
||||
fi
|
||||
|
||||
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
|
||||
|
||||
if [ ! -f "$executable" ]
|
||||
then
|
||||
mvn clean package
|
||||
fi
|
||||
|
||||
# purge lib/doc folder
|
||||
echo "purge ruby petstore lib, docs folder"
|
||||
rm -Rf samples/openapi3/client/petstore/ruby-faraday/lib
|
||||
rm -Rf samples/openapi3/client/petstore/ruby-faraday/docs
|
||||
|
||||
# purge test files other than integration test
|
||||
# NOTE: spec/custom/*.rb and spec/petstore_helper.rb are not generated files
|
||||
echo "purge ruby petstore spec"
|
||||
find samples/openapi3/client/petstore/ruby-faraday/spec -type d -not -name spec -not -name custom | xargs rm -Rf
|
||||
find samples/openapi3/client/petstore/ruby-faraday/spec -type f -not -name petstore_helper.rb -not -iwholename '*/spec/custom/*' | xargs rm -Rf
|
||||
|
||||
# if you've executed sbt assembly previously it will use that instead.
|
||||
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
|
||||
ags="generate -t modules/openapi-generator/src/main/resources/ruby-client -i modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml -g ruby -c bin/openapi3/ruby-petstore-faraday.json -o samples/openapi3/client/petstore/ruby-faraday --additional-properties skipFormModel=true $@"
|
||||
|
||||
java $JAVA_OPTS -jar $executable $ags
|
6
bin/openapi3/ruby-petstore-faraday.json
Normal file
6
bin/openapi3/ruby-petstore-faraday.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"gemName": "petstore",
|
||||
"moduleName": "Petstore",
|
||||
"library": "faraday",
|
||||
"gemVersion": "1.0.0"
|
||||
}
|
32
bin/ruby-client-petstore-faraday.sh
Executable file
32
bin/ruby-client-petstore-faraday.sh
Executable file
@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
SCRIPT="$0"
|
||||
echo "# START SCRIPT: $SCRIPT"
|
||||
|
||||
while [ -h "$SCRIPT" ] ; do
|
||||
ls=`ls -ld "$SCRIPT"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
SCRIPT="$link"
|
||||
else
|
||||
SCRIPT=`dirname "$SCRIPT"`/"$link"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -d "${APP_DIR}" ]; then
|
||||
APP_DIR=`dirname "$SCRIPT"`/..
|
||||
APP_DIR=`cd "${APP_DIR}"; pwd`
|
||||
fi
|
||||
|
||||
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
|
||||
|
||||
if [ ! -f "$executable" ]
|
||||
then
|
||||
mvn -B clean package
|
||||
fi
|
||||
|
||||
# if you've executed sbt assembly previously it will use that instead.
|
||||
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
|
||||
ags="generate -t modules/openapi-generator/src/main/resources/ruby-client -i modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -g ruby -c bin/ruby-petstore-faraday.json -o samples/client/petstore/ruby-faraday $@"
|
||||
|
||||
java $JAVA_OPTS -jar $executable $ags
|
6
bin/ruby-petstore-faraday.json
Normal file
6
bin/ruby-petstore-faraday.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"gemName": "petstore",
|
||||
"moduleName": "Petstore",
|
||||
"library": "faraday",
|
||||
"gemVersion": "1.0.0"
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"gemName": "petstore",
|
||||
"library": "typhoeus",
|
||||
"moduleName": "Petstore",
|
||||
"gemVersion": "1.0.0"
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
# Generate clients:
|
||||
./bin/spring-cloud-feign-petstore.sh
|
||||
./bin/spring-cloud-feign-async-petstore.sh
|
||||
./bin/spring-stubs.sh
|
||||
|
||||
# Generate spring-mvc servers:
|
||||
|
35
bin/spring-cloud-feign-async-petstore.sh
Executable file
35
bin/spring-cloud-feign-async-petstore.sh
Executable file
@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
|
||||
SCRIPT="$0"
|
||||
echo "# START SCRIPT: $SCRIPT"
|
||||
|
||||
while [ -h "$SCRIPT" ] ; do
|
||||
ls=`ls -ld "$SCRIPT"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
SCRIPT="$link"
|
||||
else
|
||||
SCRIPT=`dirname "$SCRIPT"`/"$link"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -d "${APP_DIR}" ]; then
|
||||
APP_DIR=`dirname "$SCRIPT"`/..
|
||||
APP_DIR=`cd "${APP_DIR}"; pwd`
|
||||
fi
|
||||
|
||||
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
|
||||
|
||||
if [ ! -f "$executable" ]
|
||||
then
|
||||
mvn -B clean package
|
||||
fi
|
||||
|
||||
# if you've executed sbt assembly previously it will use that instead.
|
||||
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
|
||||
ags="generate -t modules/openapi-generator/src/main/resources/JavaSpring/libraries/spring-cloud -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g spring -c bin/spring-cloud-feign-petstore.json -o samples/client/petstore/spring-cloud-async --additional-properties hideGenerationTimestamp=true,java8=true,async=true $@"
|
||||
|
||||
echo "Removing files and folders under samples/client/petstore/spring-cloud-async/src/main"
|
||||
rm -rf samples/client/petstore/spring-cloud-async/src/main
|
||||
find samples/client/petstore/spring-cloud-async -maxdepth 1 -type f ! -name "README.md" -exec rm {} +
|
||||
java $JAVA_OPTS -jar $executable $ags
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"npmName": "@openapitools/typescript-angular-petstore",
|
||||
"npmVersion": "1.0.0",
|
||||
"npmRepository" : "https://skimdb.npmjs.com/registry",
|
||||
"snapshot" : false
|
||||
"stringEnums": true,
|
||||
"npmRepository": "https://skimdb.npmjs.com/registry",
|
||||
"snapshot": false
|
||||
}
|
||||
|
@ -3,5 +3,6 @@
|
||||
./bin/typescript-axios-petstore-target-es6.sh
|
||||
./bin/typescript-axios-petstore-with-npm-version.sh
|
||||
./bin/typescript-axios-petstore-with-npm-version-and-separate-models-and-api.sh
|
||||
./bin/typescript-axios-petstore-with-complex-headers.sh
|
||||
./bin/typescript-axios-petstore-interfaces.sh
|
||||
./bin/typescript-axios-petstore.sh
|
||||
|
32
bin/typescript-axios-petstore-with-complex-headers.sh
Executable file
32
bin/typescript-axios-petstore-with-complex-headers.sh
Executable file
@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
SCRIPT="$0"
|
||||
echo "# START SCRIPT: $SCRIPT"
|
||||
|
||||
while [ -h "$SCRIPT" ] ; do
|
||||
ls=`ls -ld "$SCRIPT"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
SCRIPT="$link"
|
||||
else
|
||||
SCRIPT=`dirname "$SCRIPT"`/"$link"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -d "${APP_DIR}" ]; then
|
||||
APP_DIR=`dirname "$SCRIPT"`/..
|
||||
APP_DIR=`cd "${APP_DIR}"; pwd`
|
||||
fi
|
||||
|
||||
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
|
||||
|
||||
if [ ! -f "$executable" ]
|
||||
then
|
||||
mvn -B clean package
|
||||
fi
|
||||
|
||||
# if you've executed sbt assembly previously it will use that instead.
|
||||
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
|
||||
ags="generate -i modules/openapi-generator/src/test/resources/3_0/petstore-with-complex-headers.yaml -g typescript-axios -o samples/client/petstore/typescript-axios/builds/with-complex-headers $@"
|
||||
|
||||
java $JAVA_OPTS -jar $executable $ags
|
@ -13,7 +13,7 @@ sleep 5
|
||||
declare -a scripts=(
|
||||
# SAMPLES
|
||||
"./bin/openapi3/ruby-client-petstore.sh"
|
||||
"./bin/ruby-client-petstore.sh"
|
||||
"./bin/openapi3/ruby-client-faraday-petstore.sh"
|
||||
"./bin/java-petstore-all.sh"
|
||||
"./bin/java-jaxrs-petstore-server-all.sh"
|
||||
"./bin/java-msf4j-petstore-server.sh"
|
||||
|
10
bin/windows/ocaml-petstore.bat
Executable file
10
bin/windows/ocaml-petstore.bat
Executable file
@ -0,0 +1,10 @@
|
||||
set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar
|
||||
|
||||
If Not Exist %executable% (
|
||||
mvn clean package
|
||||
)
|
||||
|
||||
REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M -DloggerPath=conf/log4j.properties
|
||||
set ags=generate -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g ocaml -o samples\client\petstore\ocaml
|
||||
|
||||
java %JAVA_OPTS% -jar %executable% %ags%
|
10
bin/windows/python-experimental-petstore.bat
Normal file
10
bin/windows/python-experimental-petstore.bat
Normal file
@ -0,0 +1,10 @@
|
||||
set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar
|
||||
|
||||
If Not Exist %executable% (
|
||||
mvn clean package
|
||||
)
|
||||
|
||||
REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M
|
||||
set ags=generate -i modules\openapi-generator\src\test\resources\2_0\petstore-with-fake-endpoints-models-for-testing.yaml -g python-experimental -o samples\client\petstore\python-experimental -DpackageName=petstore_api
|
||||
|
||||
java %JAVA_OPTS% -jar %executable% %ags%
|
@ -2,6 +2,7 @@
|
||||
|
||||
call bin\windows\typescript-axios-petstore.bat
|
||||
call bin\windows\typescript-axios-petstore-target-es6.bat
|
||||
call bin\windows\typescript-axios-petstore-with-complex-headers.bat
|
||||
call bin\windows\typescript-axios-petstore-with-npm-version.bat
|
||||
call bin\windows\typescript-axios-petstore-interfaces.bat
|
||||
call bin\windows\typescript-axios-petstore-with-npm-version-and-separate-models-and-api.bat
|
12
bin/windows/typescript-axios-petstore-with-complex-headers.bat
Executable file
12
bin/windows/typescript-axios-petstore-with-complex-headers.bat
Executable file
@ -0,0 +1,12 @@
|
||||
@ECHO OFF
|
||||
|
||||
set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar
|
||||
|
||||
If Not Exist %executable% (
|
||||
mvn clean package
|
||||
)
|
||||
|
||||
REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M
|
||||
set ags=generate -i modules\openapi-generator\src\test\resources\3_0\petstore-with-complex-headers.yaml -g typescript-axios -o samples\client\petstore\typescript-axios\builds\with-complex-headers
|
||||
|
||||
java %JAVA_OPTS% -jar %executable% %ags%
|
@ -39,6 +39,7 @@ The following generators are available:
|
||||
- [kotlin](generators/kotlin.md)
|
||||
- [lua](generators/lua.md)
|
||||
- [objc](generators/objc.md)
|
||||
- [ocaml](generators/ocaml.md)
|
||||
- [perl](generators/perl.md)
|
||||
- [php](generators/php.md)
|
||||
- [powershell](generators/powershell.md)
|
||||
@ -93,6 +94,7 @@ The following generators are available:
|
||||
- [jaxrs-spec](generators/jaxrs-spec.md)
|
||||
- [kotlin-server](generators/kotlin-server.md)
|
||||
- [kotlin-spring](generators/kotlin-spring.md)
|
||||
- [nodejs-express-server](generators/nodejs-express-server.md) (beta)
|
||||
- [nodejs-server-deprecated](generators/nodejs-server-deprecated.md) (deprecated)
|
||||
- [php-laravel](generators/php-laravel.md)
|
||||
- [php-lumen](generators/php-lumen.md)
|
||||
|
14
docs/generators/nodejs-express-server.md
Normal file
14
docs/generators/nodejs-express-server.md
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
---
|
||||
id: generator-opts-server-nodejs-express-server
|
||||
title: Config Options for nodejs-express-server
|
||||
sidebar_label: nodejs-express-server
|
||||
---
|
||||
|
||||
| Option | Description | Values | Default |
|
||||
| ------ | ----------- | ------ | ------- |
|
||||
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|
||||
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
|
||||
|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
|
||||
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|
||||
|serverPort|TCP port to listen on.| |null|
|
13
docs/generators/ocaml-client.md
Normal file
13
docs/generators/ocaml-client.md
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
---
|
||||
id: generator-opts-client-ocaml-client
|
||||
title: Config Options for ocaml-client
|
||||
sidebar_label: ocaml-client
|
||||
---
|
||||
|
||||
| Option | Description | Values | Default |
|
||||
| ------ | ----------- | ------ | ------- |
|
||||
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|
||||
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
|
||||
|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
|
||||
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|
13
docs/generators/ocaml.md
Normal file
13
docs/generators/ocaml.md
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
---
|
||||
id: generator-opts-client-ocaml
|
||||
title: Config Options for ocaml
|
||||
sidebar_label: ocaml
|
||||
---
|
||||
|
||||
| Option | Description | Values | Default |
|
||||
| ------ | ----------- | ------ | ------- |
|
||||
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|
||||
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
|
||||
|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
|
||||
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|
@ -11,4 +11,4 @@ sidebar_label: openapi-yaml
|
||||
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
|
||||
|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
|
||||
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|
||||
|outputFile|output filename| |null|
|
||||
|outputFile|Output filename| |openapi/openapi.yaml|
|
||||
|
@ -22,3 +22,4 @@ sidebar_label: ruby
|
||||
|gemAuthor|gem author (only one is supported).| |null|
|
||||
|gemAuthorEmail|gem author email (only one is supported).| |null|
|
||||
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
|
||||
|library|HTTP library template (sub-template) to use|<dl><dt>**faraday**</dt><dd>Faraday (https://github.com/lostisland/faraday) (Beta support)</dd><dt>**typhoeus**</dt><dd>Typhoeus >= 1.0.1 (https://github.com/typhoeus/typhoeus)</dd><dl>|typhoeus|
|
||||
|
@ -26,3 +26,4 @@ sidebar_label: typescript-angular
|
||||
|modelSuffix|The suffix of the generated model.| |null|
|
||||
|modelFileSuffix|The suffix of the file of the generated model (model<suffix>.ts).| |null|
|
||||
|fileNaming|Naming convention for the output files: 'camelCase', 'kebab-case'.| |camelCase|
|
||||
|stringEnums|Generate string enums instead of objects for enum values.| |false|
|
||||
|
@ -16,7 +16,7 @@ The transform logic needs to implement [CodegenConfig.java](https://github.com/o
|
||||
> OpenAPI Generator applies user-defined templates via options:
|
||||
> * CLI: `-t/--template` CLI options
|
||||
> * Maven Plugin: `templateDirectory`
|
||||
> * Gradle Plugin: `templateDir`
|
||||
> * Gradle Plugin: `templateDir`
|
||||
|
||||
Built-in templates are written in Mustache and processed by [jmustache](https://github.com/samskivert/jmustache). Beginning with version 4.0.0, we support experimental Handlebars and user-defined template engines via plugins.
|
||||
|
||||
@ -26,7 +26,7 @@ OpenAPI Generator supports user-defined templates. This approach is often the ea
|
||||
|
||||
### Custom Logic
|
||||
|
||||
For this example, let's modify a Java client to use AOP via [jcabi/jcabi-aspects](https://github.com/jcabi/jcabi-aspects). We'll log API method execution at the `INFO` level. The jcabi-aspects project could also be used to implement method retries on failures; this would be a great exercise to further play around with templating.
|
||||
For this example, let's modify a Java client to use AOP via [jcabi/jcabi-aspects](https://github.com/jcabi/jcabi-aspects). We'll log API method execution at the `INFO` level. The jcabi-aspects project could also be used to implement method retries on failures; this would be a great exercise to further play around with templating.
|
||||
|
||||
The Java generator supports a `library` option. This option works by defining base templates, then applying library-specific template overrides. This allows for template reuse for libraries sharing the same programming language. Templates defined as a library need only modify or extend the templates concerning the library, and generation falls back to the root templates (the "defaults") when not extended by the library. Generators which support the `library` option will only support the libraries known by the generator at compile time, and will throw a runtime error if you try to provide a custom library name.
|
||||
|
||||
@ -77,7 +77,7 @@ index 3b40702..a6d12e0 100644
|
||||
+++ b/libraries/resteasy/build.gradle.mustache
|
||||
@@ -134,6 +134,7 @@ ext {
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
+ compile "com.jcabi:jcabi-aspects:0.22.6"
|
||||
compile "io.swagger:swagger-annotations:$swagger_annotations_version"
|
||||
@ -95,7 +95,7 @@ index a4d0f9f..49b17c7 100644
|
||||
+++ b/libraries/resteasy/api.mustache
|
||||
@@ -1,5 +1,6 @@
|
||||
package {{package}};
|
||||
|
||||
|
||||
+import com.jcabi.aspects.Loggable;
|
||||
import {{invokerPackage}}.ApiException;
|
||||
import {{invokerPackage}}.ApiClient;
|
||||
@ -134,7 +134,7 @@ index 04a9d55..7a93c50 100644
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'eclipse'
|
||||
+apply plugin: 'aspectj'
|
||||
|
||||
|
||||
group = '{{groupId}}'
|
||||
version = '{{artifactVersion}}'
|
||||
@@ -12,6 +13,7 @@ buildscript {
|
||||
@ -144,14 +144,14 @@ index 04a9d55..7a93c50 100644
|
||||
+ classpath "net.uberfoo.gradle:gradle-aspectj:2.2"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -140,9 +142,18 @@ ext {
|
||||
jersey_version = "1.19.4"
|
||||
jodatime_version = "2.9.9"
|
||||
junit_version = "4.12"
|
||||
+ aspectjVersion = '1.9.0'
|
||||
}
|
||||
|
||||
|
||||
+sourceCompatibility = '1.8'
|
||||
+targetCompatibility = '1.8'
|
||||
+
|
||||
@ -199,7 +199,7 @@ Make sure your custom template compiles:
|
||||
```bash
|
||||
cd ~/.openapi-generator/example
|
||||
gradle assemble
|
||||
# or, regenerate the wrapper
|
||||
# or, regenerate the wrapper
|
||||
gradle wrapper --gradle-version 4.8 --distribution-type all
|
||||
./gradlew assemble
|
||||
```
|
||||
@ -291,7 +291,7 @@ Modifications to the new project's `build.gradle` should be made in the `plugins
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.3.11'
|
||||
id "com.github.johnrengelman.shadow" version "5.0.0"
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
compile "org.openapitools:openapi-generator-core:4.0.0-SNAPSHOT"
|
||||
@ -301,7 +301,7 @@ Modifications to the new project's `build.gradle` should be made in the `plugins
|
||||
|
||||
The above configuration for the `shadow` plugin is strictly optional. It is not needed, for instance, if you plan to publish your adapter and consume it via the Maven or Gradle plugins.
|
||||
|
||||
Next, create a new class file called `PebbleTemplateEngineAdapter` under `src/kotlin`. We'll define the template adapter's name as `pebble` and we'll also list this as the only supported file extension. We'll implement the adapter by extending `AbstractTemplatingEngineAdapter`, which includes reusable logic, such as retrieving a list of all possible template names for our provided template extensions(s).
|
||||
Next, create a new class file called `PebbleTemplateEngineAdapter` under `src/kotlin`. We'll define the template adapter's name as `pebble` and we'll also list this as the only supported file extension. We'll implement the adapter by extending `AbstractTemplatingEngineAdapter`, which includes reusable logic, such as retrieving a list of all possible template names for our provided template extensions(s).
|
||||
|
||||
The class in its simplest form looks like this (with inline comments):
|
||||
|
||||
@ -374,7 +374,7 @@ import (
|
||||
{% endfor %}
|
||||
)
|
||||
|
||||
type Generated{{classname}}Servicer
|
||||
type Generated{{classname}}Servicer
|
||||
|
||||
// etc
|
||||
```
|
||||
@ -402,7 +402,7 @@ type {{item.classname}} struct {
|
||||
|
||||
> Find object structures passed to templates later in this document's **Structures** section.
|
||||
|
||||
Finally, we can compile some code by explicitly defining our classpath and jar entrypoint for CLI (be sure to modify `/your/path` below)
|
||||
Finally, we can compile some code by explicitly defining our classpath and jar entrypoint for CLI (be sure to modify `/your/path` below)
|
||||
|
||||
```bash
|
||||
java $JAVA_OPTS -cp /your/path/build/libs/pebble-template-adapter-1.0-SNAPSHOT-all.jar:modules/openapi-generator-cli/target/openapi-generator-cli.jar \
|
||||
@ -428,49 +428,49 @@ Examples for the following structures will be presented using the following spec
|
||||
|
||||
```yaml
|
||||
swagger: "2.0"
|
||||
info:
|
||||
info:
|
||||
version: "1.0.0"
|
||||
title: "Swagger Petstore"
|
||||
description: "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification"
|
||||
termsOfService: "http://swagger.io/terms/"
|
||||
contact:
|
||||
contact:
|
||||
name: "Swagger API Team"
|
||||
license:
|
||||
license:
|
||||
name: "MIT"
|
||||
host: "petstore.swagger.io"
|
||||
basePath: "/api"
|
||||
schemes:
|
||||
schemes:
|
||||
- "http"
|
||||
consumes:
|
||||
consumes:
|
||||
- "application/json"
|
||||
produces:
|
||||
produces:
|
||||
- "application/json"
|
||||
paths:
|
||||
/pets:
|
||||
get:
|
||||
paths:
|
||||
/pets:
|
||||
get:
|
||||
description: "Returns all pets from the system that the user has access to"
|
||||
produces:
|
||||
produces:
|
||||
- "application/json"
|
||||
responses:
|
||||
responses:
|
||||
"200":
|
||||
description: "A list of pets."
|
||||
schema:
|
||||
schema:
|
||||
type: "array"
|
||||
items:
|
||||
items:
|
||||
$ref: "#/definitions/Pet"
|
||||
definitions:
|
||||
Pet:
|
||||
definitions:
|
||||
Pet:
|
||||
type: "object"
|
||||
required:
|
||||
required:
|
||||
- "id"
|
||||
- "name"
|
||||
properties:
|
||||
id:
|
||||
properties:
|
||||
id:
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
name:
|
||||
name:
|
||||
type: "string"
|
||||
tag:
|
||||
tag:
|
||||
type: "string"
|
||||
|
||||
```
|
||||
@ -478,9 +478,9 @@ Examples for the following structures will be presented using the following spec
|
||||
### Operations
|
||||
|
||||
> Inspect operation structures passed to templates with system property `-DdebugOpenAPI`
|
||||
>
|
||||
>
|
||||
> Example:
|
||||
>
|
||||
>
|
||||
> ```bash
|
||||
> openapi-generator generate -g go \
|
||||
> -o out \
|
||||
@ -510,9 +510,9 @@ Here, an Operation with tag `Pet` will generate two files: `SWGPetApi.h` and `SW
|
||||
### Models
|
||||
|
||||
> Inspect models passed to templates with system property `-DdebugModels`
|
||||
>
|
||||
>
|
||||
> Execute:
|
||||
>
|
||||
>
|
||||
> ```bash
|
||||
> openapi-generator generate -g go \
|
||||
> -o out \
|
||||
@ -730,14 +730,14 @@ Templates are passed redundant properties, depending on the semantics of the arr
|
||||
* `readOnlyVars` lists all model properties marked with `readonly` in the spec document
|
||||
* `allVars` lists all model properties. This may include the same set as `vars`, but may also include generator-defined properties
|
||||
|
||||
We expose the same properties in multiple sets because this allows us to conditionally iterate over properties based on some condition ("is it required" or "is it readonly"). This is driven by the use of the logic-less Mustache templates. It is possible that models passed to the templating engine may be cleaned up as we support more template engines, but such an effort will go through a deprecation phase and would be communicated at runtime through log messages.
|
||||
We expose the same properties in multiple sets because this allows us to conditionally iterate over properties based on some condition ("is it required" or "is it readonly"). This is driven by the use of the logic-less Mustache templates. It is possible that models passed to the templating engine may be cleaned up as we support more template engines, but such an effort will go through a deprecation phase and would be communicated at runtime through log messages.
|
||||
|
||||
### supportingFiles
|
||||
|
||||
> Inspect supportingFiles passed to templates with system property `-DdebugSupportingFiles`
|
||||
>
|
||||
>
|
||||
> Execute:
|
||||
>
|
||||
>
|
||||
> ```bash
|
||||
> openapi-generator generate -g go \
|
||||
> -o out \
|
||||
@ -755,10 +755,25 @@ Supporting files can either be processed through the templating engine or copied
|
||||
|
||||
> This is a very limited list of variable name explanations. Feel free to [open a pull request](https://github.com/OpenAPITools/openapi-generator/pull/new/master) to add to this documentation!
|
||||
|
||||
- **complexType**: stores the name of the model (e.g. Pet)
|
||||
- **complexType**: stores the name of the model (e.g. Pet)
|
||||
- **isContainer**: true if the parameter or property is an array or a map.
|
||||
- **isPrimitiveType**: true if the parameter or property type is a primitive type (e.g. string, integer, etc) as defined in the spec.
|
||||
|
||||
## Mustache Lambdas
|
||||
|
||||
Many generators (*those extending DefaultCodegen*) come with a small set of lambda functions available under the key `lambda`:
|
||||
|
||||
- `lowercase` - Converts all of the characters in this fragment to lower case using the rules of the `ROOT` locale.
|
||||
- `uppercase` - Converts all of the characters in this fragment to upper case using the rules of the `ROOT` locale.
|
||||
- `titlecase` - Converts text in a fragment to title case. For example `once upon a time` to `Once Upon A Time`.
|
||||
- `camelcase` - Converts text in a fragment to camelCase. For example `Input-text` to `inputText`.
|
||||
- `indented` - Prepends 4 spaces indention from second line of a fragment on. First line will be indented by Mustache.
|
||||
- `indented_8` - Prepends 8 spaces indention from second line of a fragment on. First line will be indented by Mustache.
|
||||
- `indented_12` - Prepends 12 spaces indention from second line of a fragment on. First line will be indented by Mustache.
|
||||
- `indented_16` -Prepends 16 spaces indention from second line of a fragment on. First line will be indented by Mustache.
|
||||
|
||||
Lambda is invoked by `lambda.[lambda name]` expression. For example: `{{#lambda.lowercase}}FRAGMENT TO LOWERCASE{{/lambda.lowercase}}` to lower case text between `lambda.lowercase`.
|
||||
|
||||
## Extensions
|
||||
|
||||
OpenAPI supports a concept called "Extensions". These are called "Specification Extensions" [in 3.x](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#specificationExtensions) and "Vendor Extensions" [in 2.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#vendorExtensions).
|
||||
@ -861,7 +876,7 @@ paths:
|
||||
|
||||
#### x-mysqlSchema
|
||||
|
||||
MySQL schema generator creates vendor extensions based on openapi `dataType` and `dataFormat`. When user defined extensions with same key already exists codegen accepts those as is. It means it won't validate properties or correct it for you. Every model in `definitions` can contain table related and column related extensions like in example below:
|
||||
MySQL schema generator creates vendor extensions based on openapi `dataType` and `dataFormat`. When user defined extensions with same key already exists codegen accepts those as is. It means it won't validate properties or correct it for you. Every model in `definitions` can contain table related and column related extensions like in example below:
|
||||
|
||||
```yaml
|
||||
definitions:
|
||||
|
@ -45,7 +45,7 @@ compileJava.dependsOn tasks.openApiGenerate
|
||||
[source,group]
|
||||
----
|
||||
plugins {
|
||||
id "org.openapi.generator" version "4.0.3"
|
||||
id "org.openapi.generator" version "4.1.0"
|
||||
}
|
||||
----
|
||||
|
||||
@ -61,7 +61,7 @@ buildscript {
|
||||
// url "https://plugins.gradle.org/m2/"
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.openapitools:openapi-generator-gradle-plugin:4.0.3"
|
||||
classpath "org.openapitools:openapi-generator-gradle-plugin:4.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -609,7 +609,7 @@ buildscript {
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.2.1'
|
||||
classpath('org.openapitools:openapi-generator-gradle-plugin:4.0.3') {
|
||||
classpath('org.openapitools:openapi-generator-gradle-plugin:4.1.0') {
|
||||
exclude group: 'com.google.guava'
|
||||
}
|
||||
}
|
||||
|
@ -17,5 +17,5 @@ gradle generateGoWithInvalidSpec
|
||||
The samples can be tested against other versions of the plugin using the `openApiGeneratorVersion` property. For example:
|
||||
|
||||
```bash
|
||||
gradle -PopenApiGeneratorVersion=4.0.3 openApiValidate
|
||||
gradle -PopenApiGeneratorVersion=4.1.0 openApiValidate
|
||||
```
|
||||
|
@ -1,3 +1,3 @@
|
||||
# RELEASE_VERSION
|
||||
openApiGeneratorVersion=4.0.3
|
||||
openApiGeneratorVersion=4.1.0
|
||||
# /RELEASE_VERSION
|
||||
|
@ -12,7 +12,7 @@ Add to your `build->plugins` section (default phase is `generate-sources` phase)
|
||||
<groupId>org.openapitools</groupId>
|
||||
<artifactId>openapi-generator-maven-plugin</artifactId>
|
||||
<!-- RELEASE_VERSION -->
|
||||
<version>4.0.3</version>
|
||||
<version>4.1.0</version>
|
||||
<!-- /RELEASE_VERSION -->
|
||||
<executions>
|
||||
<execution>
|
||||
|
@ -13,7 +13,7 @@
|
||||
<groupId>org.openapitools</groupId>
|
||||
<artifactId>openapi-generator-maven-plugin</artifactId>
|
||||
<!-- RELEASE_VERSION -->
|
||||
<version>4.0.3</version>
|
||||
<version>4.1.1-SNAPSHOT</version>
|
||||
<!-- /RELEASE_VERSION -->
|
||||
<executions>
|
||||
<execution>
|
||||
@ -88,6 +88,13 @@
|
||||
<version>${jersey-version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- @Nullable annotation -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON processing: jackson -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.jaxrs</groupId>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<groupId>org.openapitools</groupId>
|
||||
<artifactId>openapi-generator-maven-plugin</artifactId>
|
||||
<!-- RELEASE_VERSION -->
|
||||
<version>4.0.3</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<!-- /RELEASE_VERSION -->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@ -101,6 +101,13 @@
|
||||
<version>${jersey-version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- @Nullable annotation -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON processing: jackson -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.jaxrs</groupId>
|
||||
|
@ -13,7 +13,7 @@
|
||||
<groupId>org.openapitools</groupId>
|
||||
<artifactId>openapi-generator-maven-plugin</artifactId>
|
||||
<!-- RELEASE_VERSION -->
|
||||
<version>4.0.3</version>
|
||||
<version>4.1.0</version>
|
||||
<!-- /RELEASE_VERSION -->
|
||||
<executions>
|
||||
<execution>
|
||||
|
@ -13,7 +13,7 @@
|
||||
<groupId>org.openapitools</groupId>
|
||||
<artifactId>openapi-generator-maven-plugin</artifactId>
|
||||
<!-- RELEASE_VERSION -->
|
||||
<version>4.0.3</version>
|
||||
<version>4.1.0</version>
|
||||
<!-- /RELEASE_VERSION -->
|
||||
<executions>
|
||||
<execution>
|
||||
|
@ -240,13 +240,10 @@ public class DefaultCodegen implements CodegenConfig {
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey("lambda")) {
|
||||
LOGGER.warn("A property named 'lambda' already exists. Mustache lambdas renamed from 'lambda' to '_lambda'. " +
|
||||
"You'll likely need to use a custom template, " +
|
||||
"see https://github.com/OpenAPITools/openapi-generator/blob/master/docs/templating.md. ");
|
||||
additionalProperties.put("_lambda", lambdas);
|
||||
} else {
|
||||
additionalProperties.put("lambda", lambdas);
|
||||
LOGGER.error("A property called 'lambda' already exists in additionalProperties");
|
||||
throw new RuntimeException("A property called 'lambda' already exists in additionalProperties");
|
||||
}
|
||||
additionalProperties.put("lambda", lambdas);
|
||||
}
|
||||
|
||||
// override with any special post-processing for all models
|
||||
@ -1870,6 +1867,9 @@ public class DefaultCodegen implements CodegenConfig {
|
||||
}
|
||||
}
|
||||
|
||||
if(composed.getRequired() != null) {
|
||||
required.addAll(composed.getRequired());
|
||||
}
|
||||
addVars(m, unaliasPropertySchema(properties), required, unaliasPropertySchema(allProperties), allRequired);
|
||||
|
||||
// end of code block for composed schema
|
||||
@ -1975,6 +1975,10 @@ public class DefaultCodegen implements CodegenConfig {
|
||||
addProperties(properties, required, component);
|
||||
}
|
||||
|
||||
if(schema.getRequired() != null) {
|
||||
required.addAll(schema.getRequired());
|
||||
}
|
||||
|
||||
if (composedSchema.getOneOf() != null) {
|
||||
throw new RuntimeException("Please report the issue: Cannot process oneOf (Composed Scheme) in addProperties: " + schema);
|
||||
}
|
||||
@ -4017,6 +4021,19 @@ public class DefaultCodegen implements CodegenConfig {
|
||||
* @return sanitized string
|
||||
*/
|
||||
public String sanitizeName(String name, String removeCharRegEx) {
|
||||
return sanitizeName(name, removeCharRegEx, new ArrayList<String>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize name (parameter, property, method, etc)
|
||||
*
|
||||
* @param name string to be sanitize
|
||||
* @param removeCharRegEx a regex containing all char that will be removed
|
||||
* @param exceptionList a list of matches which should not be sanitized (i.e expections)
|
||||
* @return sanitized string
|
||||
*/
|
||||
@SuppressWarnings("static-method")
|
||||
public String sanitizeName(String name, String removeCharRegEx, ArrayList<String> exceptionList) {
|
||||
// NOTE: performance wise, we should have written with 2 replaceAll to replace desired
|
||||
// character with _ or empty character. Below aims to spell out different cases we've
|
||||
// encountered so far and hopefully make it easier for others to add more special
|
||||
@ -4034,27 +4051,27 @@ public class DefaultCodegen implements CodegenConfig {
|
||||
}
|
||||
|
||||
// input[] => input
|
||||
name = name.replaceAll("\\[\\]", ""); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
|
||||
name = this.sanitizeValue(name, "\\[\\]", "", exceptionList);
|
||||
|
||||
// input[a][b] => input_a_b
|
||||
name = name.replaceAll("\\[", "_");
|
||||
name = name.replaceAll("\\]", "");
|
||||
name = this.sanitizeValue(name, "\\[", "_", exceptionList);
|
||||
name = this.sanitizeValue(name, "\\]", "", exceptionList);
|
||||
|
||||
// input(a)(b) => input_a_b
|
||||
name = name.replaceAll("\\(", "_");
|
||||
name = name.replaceAll("\\)", "");
|
||||
name = this.sanitizeValue(name, "\\(", "_", exceptionList);
|
||||
name = this.sanitizeValue(name, "\\)", "", exceptionList);
|
||||
|
||||
// input.name => input_name
|
||||
name = name.replaceAll("\\.", "_");
|
||||
name = this.sanitizeValue(name, "\\.", "_", exceptionList);
|
||||
|
||||
// input-name => input_name
|
||||
name = name.replaceAll("-", "_");
|
||||
name = this.sanitizeValue(name, "-", "_", exceptionList);
|
||||
|
||||
// a|b => a_b
|
||||
name = name.replace("|", "_");
|
||||
name = this.sanitizeValue(name, "\\|", "_", exceptionList);
|
||||
|
||||
// input name and age => input_name_and_age
|
||||
name = name.replaceAll(" ", "_");
|
||||
name = this.sanitizeValue(name, " ", "_", exceptionList);
|
||||
|
||||
// /api/films/get => _api_films_get
|
||||
// \api\films\get => _api_films_get
|
||||
@ -4072,6 +4089,13 @@ public class DefaultCodegen implements CodegenConfig {
|
||||
return name;
|
||||
}
|
||||
|
||||
private String sanitizeValue(String value, String replaceMatch, String replaceValue, ArrayList<String> exceptionList) {
|
||||
if (exceptionList.size() == 0 || !exceptionList.contains(replaceMatch)) {
|
||||
return value.replaceAll(replaceMatch, replaceValue);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize tag
|
||||
*
|
||||
@ -4908,6 +4932,15 @@ public class DefaultCodegen implements CodegenConfig {
|
||||
codegenParameter.dataType = codegenProperty.dataType;
|
||||
codegenParameter.description = codegenProperty.description;
|
||||
codegenParameter.paramName = toParamName(codegenParameter.baseName);
|
||||
codegenParameter.minimum = codegenProperty.minimum;
|
||||
codegenParameter.maximum = codegenProperty.maximum;
|
||||
codegenParameter.exclusiveMinimum = codegenProperty.exclusiveMinimum;
|
||||
codegenParameter.exclusiveMaximum = codegenProperty.exclusiveMaximum;
|
||||
codegenParameter.minLength = codegenProperty.minLength;
|
||||
codegenParameter.maxLength = codegenProperty.maxLength;
|
||||
codegenParameter.pattern = codegenProperty.pattern;
|
||||
|
||||
|
||||
|
||||
if (codegenProperty.complexType != null) {
|
||||
imports.add(codegenProperty.complexType);
|
||||
|
@ -407,9 +407,19 @@ public class InlineModelResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique model name. Non-alphanumeric characters will be replaced
|
||||
* with underscores
|
||||
*
|
||||
* @param title String title field in the schema if present
|
||||
* @param key String model name
|
||||
*/
|
||||
private String resolveModelName(String title, String key) {
|
||||
if (title == null) {
|
||||
return uniqueName(key);
|
||||
// for auto-generated schema name, replace non-alphanumeric characters with underscore
|
||||
// to avoid bugs with schema look up with inline schema created on the fly
|
||||
// e.g. io.schema.User_name => io_schema_User_name
|
||||
return uniqueName(key).replaceAll("[^A-Za-z0-9]", "_");
|
||||
} else {
|
||||
return uniqueName(title);
|
||||
}
|
||||
@ -589,4 +599,4 @@ public class InlineModelResolver {
|
||||
target.addExtension(extName, vendorExtensions.get(extName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,13 +153,14 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
|
||||
"DateTime?",
|
||||
"DateTime",
|
||||
"DateTimeOffset?",
|
||||
"DataTimeOffset",
|
||||
"DateTimeOffset",
|
||||
"Boolean",
|
||||
"Double",
|
||||
"Int32",
|
||||
"Int64",
|
||||
"Float",
|
||||
"Guid?",
|
||||
"Guid",
|
||||
"System.IO.Stream", // not really a primitive, we include it to avoid model import
|
||||
"Object")
|
||||
);
|
||||
@ -192,7 +193,7 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
|
||||
|
||||
// nullable type
|
||||
nullableType = new HashSet<String>(
|
||||
Arrays.asList("decimal", "bool", "int", "float", "long", "double", "DateTime", "Guid")
|
||||
Arrays.asList("decimal", "bool", "int", "float", "long", "double", "DateTime", "DateTimeOffset", "Guid")
|
||||
);
|
||||
// value Types
|
||||
valueTypes = new HashSet<String>(
|
||||
@ -226,9 +227,9 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
|
||||
public void useDateTimeOffset(boolean flag) {
|
||||
this.useDateTimeOffsetFlag = flag;
|
||||
if (flag) {
|
||||
typeMapping.put("DateTime", "DateTimeOffset?");
|
||||
typeMapping.put("DateTime", "DateTimeOffset");
|
||||
} else {
|
||||
typeMapping.put("DateTime", "DateTime?");
|
||||
typeMapping.put("DateTime", "DateTime");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ package org.openapitools.codegen.languages;
|
||||
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.media.ArraySchema;
|
||||
import io.swagger.v3.oas.models.media.ComposedSchema;
|
||||
import io.swagger.v3.oas.models.media.Schema;
|
||||
import io.swagger.v3.oas.models.parameters.Parameter;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
@ -54,6 +55,9 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
|
||||
protected String npmName = null;
|
||||
protected String npmVersion = "1.0.0";
|
||||
|
||||
protected String enumSuffix = "Enum";
|
||||
protected String classEnumSeparator = ".";
|
||||
|
||||
public AbstractTypeScriptClientCodegen() {
|
||||
super();
|
||||
|
||||
@ -94,7 +98,7 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
|
||||
"object"
|
||||
));
|
||||
|
||||
languageGenericTypes = new HashSet<>(Arrays.asList(
|
||||
languageGenericTypes = new HashSet<>(Collections.singletonList(
|
||||
"Array"
|
||||
));
|
||||
|
||||
@ -144,8 +148,7 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
|
||||
if (StringUtils.isEmpty(System.getenv("TS_POST_PROCESS_FILE"))) {
|
||||
LOGGER.info("Hint: Environment variable 'TS_POST_PROCESS_FILE' (optional) not defined. E.g. to format the source code, please try 'export TS_POST_PROCESS_FILE=\"/usr/local/bin/prettier --write\"' (Linux/Mac)");
|
||||
LOGGER.info("Note: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
|
||||
}
|
||||
else if (!this.isEnablePostProcessFile()) {
|
||||
} else if (!this.isEnablePostProcessFile()) {
|
||||
LOGGER.info("Warning: Environment variable 'TS_POST_PROCESS_FILE' is set but file post-processing is not enabled. To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
|
||||
}
|
||||
|
||||
@ -177,7 +180,7 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
|
||||
this.setNpmVersion(openAPI.getInfo().getVersion());
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(SNAPSHOT) && Boolean.valueOf(additionalProperties.get(SNAPSHOT).toString())) {
|
||||
if (additionalProperties.containsKey(SNAPSHOT) && Boolean.parseBoolean(additionalProperties.get(SNAPSHOT).toString())) {
|
||||
if (npmVersion.toUpperCase(Locale.ROOT).matches("^.*-SNAPSHOT$")) {
|
||||
this.setNpmVersion(npmVersion + "." + SNAPSHOT_SUFFIX_FORMAT.format(new Date()));
|
||||
} else {
|
||||
@ -260,45 +263,45 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
|
||||
final String regex = "^.*[+*:;,.()-]+.*$";
|
||||
final Pattern pattern = Pattern.compile(regex);
|
||||
final Matcher matcher = pattern.matcher(str);
|
||||
boolean matches = matcher.matches();
|
||||
return matches;
|
||||
return matcher.matches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toModelName(String name) {
|
||||
name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
|
||||
public String toModelName(final String name) {
|
||||
ArrayList<String> exceptions = new ArrayList<String>(Arrays.asList("\\|", " "));
|
||||
String sanName = sanitizeName(name, "(?![| ])\\W", exceptions);
|
||||
|
||||
if (!StringUtils.isEmpty(modelNamePrefix)) {
|
||||
name = modelNamePrefix + "_" + name;
|
||||
sanName = modelNamePrefix + "_" + sanName;
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(modelNameSuffix)) {
|
||||
name = name + "_" + modelNameSuffix;
|
||||
sanName = sanName + "_" + modelNameSuffix;
|
||||
}
|
||||
|
||||
// model name cannot use reserved keyword, e.g. return
|
||||
if (isReservedWord(name)) {
|
||||
String modelName = camelize("model_" + name);
|
||||
LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + modelName);
|
||||
if (isReservedWord(sanName)) {
|
||||
String modelName = camelize("model_" + sanName);
|
||||
LOGGER.warn(sanName + " (reserved word) cannot be used as model name. Renamed to " + modelName);
|
||||
return modelName;
|
||||
}
|
||||
|
||||
// model name starts with number
|
||||
if (name.matches("^\\d.*")) {
|
||||
String modelName = camelize("model_" + name); // e.g. 200Response => Model200Response (after camelize)
|
||||
LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + modelName);
|
||||
if (sanName.matches("^\\d.*")) {
|
||||
String modelName = camelize("model_" + sanName); // e.g. 200Response => Model200Response (after camelize)
|
||||
LOGGER.warn(sanName + " (model name starts with number) cannot be used as model name. Renamed to " + modelName);
|
||||
return modelName;
|
||||
}
|
||||
|
||||
if (languageSpecificPrimitives.contains(name)) {
|
||||
String modelName = camelize("model_" + name);
|
||||
LOGGER.warn(name + " (model name matches existing language type) cannot be used as a model name. Renamed to " + modelName);
|
||||
if (languageSpecificPrimitives.contains(sanName)) {
|
||||
String modelName = camelize("model_" + sanName);
|
||||
LOGGER.warn(sanName + " (model name matches existing language type) cannot be used as a model name. Renamed to " + modelName);
|
||||
return modelName;
|
||||
}
|
||||
|
||||
// camelize the model name
|
||||
// phone_number => PhoneNumber
|
||||
return camelize(name);
|
||||
return camelize(sanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -549,8 +552,7 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
|
||||
|
||||
@Override
|
||||
public String toEnumName(CodegenProperty property) {
|
||||
String enumName = toModelName(property.name) + "Enum";
|
||||
|
||||
String enumName = toModelName(property.name) + enumSuffix;
|
||||
if (enumName.matches("\\d.*")) { // starts with number
|
||||
return "_" + enumName;
|
||||
} else {
|
||||
@ -569,14 +571,14 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
|
||||
// name enum with model name, e.g. StatusEnum => Pet.StatusEnum
|
||||
for (CodegenProperty var : cm.vars) {
|
||||
if (Boolean.TRUE.equals(var.isEnum)) {
|
||||
var.datatypeWithEnum = var.datatypeWithEnum.replace(var.enumName, cm.classname + "." + var.enumName);
|
||||
var.datatypeWithEnum = var.datatypeWithEnum.replace(var.enumName, cm.classname + classEnumSeparator + var.enumName);
|
||||
}
|
||||
}
|
||||
if (cm.parent != null) {
|
||||
for (CodegenProperty var : cm.allVars) {
|
||||
if (Boolean.TRUE.equals(var.isEnum)) {
|
||||
var.datatypeWithEnum = var.datatypeWithEnum
|
||||
.replace(var.enumName, cm.classname + "." + var.enumName);
|
||||
.replace(var.enumName, cm.classname + classEnumSeparator + var.enumName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -696,4 +698,14 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toAnyOfName(List<String> names, ComposedSchema composedSchema) {
|
||||
return String.join(" | ", names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toOneOfName(List<String> names, ComposedSchema composedSchema) {
|
||||
return String.join(" | ", names);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.media.Schema;
|
||||
import io.swagger.v3.parser.util.SchemaTypeUtil;
|
||||
import org.openapitools.codegen.*;
|
||||
import org.openapitools.codegen.utils.ModelUtils;
|
||||
import org.openapitools.codegen.utils.URLPathUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -326,6 +327,7 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
|
||||
supportingFiles.add(new SupportingFile("Solution.mustache", "", packageName + ".sln"));
|
||||
supportingFiles.add(new SupportingFile("gitignore", packageFolder, ".gitignore"));
|
||||
supportingFiles.add(new SupportingFile("validateModel.mustache", packageFolder + File.separator + "Attributes", "ValidateModelStateAttribute.cs"));
|
||||
supportingFiles.add(new SupportingFile("typeConverter.mustache", packageFolder + File.separator + "Converters", "CustomEnumConverter.cs"));
|
||||
supportingFiles.add(new SupportingFile("Project.csproj.mustache", packageFolder, packageName + ".csproj"));
|
||||
if (!isLibrary) {
|
||||
supportingFiles.add(new SupportingFile("Dockerfile.mustache", packageFolder, "Dockerfile"));
|
||||
@ -353,7 +355,7 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
|
||||
supportingFiles.add(new SupportingFile("Filters" + File.separator + "GeneratePathParamsValidationFilter.mustache",
|
||||
packageFolder + File.separator + "Filters", "GeneratePathParamsValidationFilter.cs"));
|
||||
}
|
||||
|
||||
|
||||
supportingFiles.add(new SupportingFile("Authentication" + File.separator + "ApiAuthentication.mustache",packageFolder + File.separator + "Authentication", "ApiAuthentication.cs"));
|
||||
}
|
||||
|
||||
@ -407,12 +409,12 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
|
||||
|
||||
@Override
|
||||
public String getNullableType(Schema p, String type) {
|
||||
boolean isNullableExpected = p.getNullable() == null || (p.getNullable() != null && p.getNullable());
|
||||
|
||||
if (isNullableExpected && languageSpecificPrimitives.contains(type + "?")) {
|
||||
return type + "?";
|
||||
} else if (languageSpecificPrimitives.contains(type)) {
|
||||
return type;
|
||||
if (languageSpecificPrimitives.contains(type)) {
|
||||
if (isSupportNullable() && ModelUtils.isNullable(p) && nullableType.contains(type)) {
|
||||
return type + "?";
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -879,15 +879,15 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getNullableType(Schema p, String type) {
|
||||
boolean isNullableExpected = p.getNullable() == null || (p.getNullable() != null && p.getNullable());
|
||||
|
||||
if (isNullableExpected && languageSpecificPrimitives.contains(type + "?")) {
|
||||
return type + "?";
|
||||
} else if (languageSpecificPrimitives.contains(type)) {
|
||||
return type;
|
||||
if (languageSpecificPrimitives.contains(type)) {
|
||||
if (isSupportNullable() && ModelUtils.isNullable(p) && nullableType.contains(type)) {
|
||||
return type + "?";
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -359,7 +359,10 @@ public class CppRestSdkClientCodegen extends AbstractCppCodegen {
|
||||
return "new " + toModelName(ModelUtils.getSimpleRef(p.get$ref())) + "()";
|
||||
} else if (ModelUtils.isStringSchema(p)) {
|
||||
return "utility::conversions::to_string_t(\"\")";
|
||||
} else if (ModelUtils.isFreeFormObject(p)) {
|
||||
return "new Object()";
|
||||
}
|
||||
|
||||
return "nullptr";
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,390 @@
|
||||
/*
|
||||
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.openapitools.codegen.languages;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.Operation;
|
||||
import io.swagger.v3.oas.models.PathItem;
|
||||
import io.swagger.v3.oas.models.PathItem.HttpMethod;
|
||||
import io.swagger.v3.oas.models.Paths;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import org.openapitools.codegen.*;
|
||||
import org.openapitools.codegen.meta.GeneratorMetadata;
|
||||
import org.openapitools.codegen.meta.Stability;
|
||||
import org.openapitools.codegen.utils.URLPathUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.openapitools.codegen.utils.StringUtils.*;
|
||||
|
||||
public class NodeJSExpressServerCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(NodeJSExpressServerCodegen.class);
|
||||
public static final String EXPORTED_NAME = "exportedName";
|
||||
public static final String SERVER_PORT = "serverPort";
|
||||
|
||||
protected String apiVersion = "1.0.0";
|
||||
protected String defaultServerPort = "8080";
|
||||
protected String implFolder = "services";
|
||||
protected String projectName = "openapi-server";
|
||||
protected String exportedName;
|
||||
|
||||
public NodeJSExpressServerCodegen() {
|
||||
super();
|
||||
|
||||
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
|
||||
.stability(Stability.BETA)
|
||||
.build();
|
||||
|
||||
outputFolder = "generated-code/nodejs-express-server";
|
||||
embeddedTemplateDir = templateDir = "nodejs-express-server";
|
||||
|
||||
setReservedWordsLowerCase(
|
||||
Arrays.asList(
|
||||
"break", "case", "class", "catch", "const", "continue", "debugger",
|
||||
"default", "delete", "do", "else", "export", "extends", "finally",
|
||||
"for", "function", "if", "import", "in", "instanceof", "let", "new",
|
||||
"return", "super", "switch", "this", "throw", "try", "typeof", "var",
|
||||
"void", "while", "with", "yield")
|
||||
);
|
||||
|
||||
additionalProperties.put("apiVersion", apiVersion);
|
||||
additionalProperties.put("implFolder", implFolder);
|
||||
|
||||
// no model file
|
||||
modelTemplateFiles.clear();
|
||||
|
||||
apiTemplateFiles.put("controller.mustache", ".js");
|
||||
apiTemplateFiles.put("service.mustache", ".js");
|
||||
|
||||
supportingFiles.add(new SupportingFile("openapi.mustache", "api", "openapi.yaml"));
|
||||
supportingFiles.add(new SupportingFile("config.mustache", "", "config.js"));
|
||||
supportingFiles.add(new SupportingFile("expressServer.mustache", "", "expressServer.js"));
|
||||
supportingFiles.add(new SupportingFile("index.mustache", "", "index.js"));
|
||||
supportingFiles.add(new SupportingFile("logger.mustache", "", "logger.js"));
|
||||
supportingFiles.add(new SupportingFile("eslintrc.mustache", "", ".eslintrc.json"));
|
||||
|
||||
// utils folder
|
||||
supportingFiles.add(new SupportingFile("utils" + File.separator + "openapiRouter.mustache", "utils", "openapiRouter.js"));
|
||||
|
||||
// controllers folder
|
||||
supportingFiles.add(new SupportingFile("controllers" + File.separator + "index.mustache", "controllers", "index.js"));
|
||||
supportingFiles.add(new SupportingFile("controllers" + File.separator + "Controller.mustache", "controllers", "Controller.js"));
|
||||
// service folder
|
||||
supportingFiles.add(new SupportingFile("services" + File.separator + "index.mustache", "services", "index.js"));
|
||||
supportingFiles.add(new SupportingFile("services" + File.separator + "Service.mustache", "services", "Service.js"));
|
||||
|
||||
// do not overwrite if the file is already present
|
||||
writeOptional(outputFolder, new SupportingFile("package.mustache", "", "package.json"));
|
||||
writeOptional(outputFolder, new SupportingFile("README.mustache", "", "README.md"));
|
||||
|
||||
cliOptions.add(new CliOption(SERVER_PORT,
|
||||
"TCP port to listen on."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apiPackage() {
|
||||
return "controllers";
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the type of generator.
|
||||
*
|
||||
* @return the CodegenType for this generator
|
||||
* @see org.openapitools.codegen.CodegenType
|
||||
*/
|
||||
@Override
|
||||
public CodegenType getTag() {
|
||||
return CodegenType.SERVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a friendly name for the generator. This will be used by the generator
|
||||
* to select the library with the -g flag.
|
||||
*
|
||||
* @return the friendly name for the generator
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "nodejs-express-server";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns human-friendly help for the generator. Provide the consumer with help
|
||||
* tips, parameters here
|
||||
*
|
||||
* @return A string value for the help message
|
||||
*/
|
||||
@Override
|
||||
public String getHelp() {
|
||||
return "Generates a NodeJS Express server (alpha). IMPORTANT: this generator may subject to breaking changes without further notice).";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toApiName(String name) {
|
||||
if (name.length() == 0) {
|
||||
return "Default";
|
||||
}
|
||||
return camelize(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toApiFilename(String name) {
|
||||
return toApiName(name) + "Controller";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apiFilename(String templateName, String tag) {
|
||||
String result = super.apiFilename(templateName, tag);
|
||||
|
||||
if (templateName.equals("service.mustache")) {
|
||||
String stringToMatch = File.separator + "controllers" + File.separator;
|
||||
String replacement = File.separator + implFolder + File.separator;
|
||||
result = result.replaceAll(Pattern.quote(stringToMatch), replacement);
|
||||
|
||||
stringToMatch = "Controller.js";
|
||||
replacement = "Service.js";
|
||||
result = result.replaceAll(Pattern.quote(stringToMatch), replacement);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
@Override
|
||||
protected String implFileFolder(String output) {
|
||||
return outputFolder + File.separator + output + File.separator + apiPackage().replace('.', File.separatorChar);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Escapes a reserved word as defined in the `reservedWords` array. Handle escaping
|
||||
* those terms here. This logic is only called if a variable matches the reserved words
|
||||
*
|
||||
* @return the escaped term
|
||||
*/
|
||||
@Override
|
||||
public String escapeReservedWord(String name) {
|
||||
if (this.reservedWordsMappings().containsKey(name)) {
|
||||
return this.reservedWordsMappings().get(name);
|
||||
}
|
||||
return "_" + name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Location to write api files. You can use the apiPackage() as defined when the class is
|
||||
* instantiated
|
||||
*/
|
||||
@Override
|
||||
public String apiFileFolder() {
|
||||
return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
public String getExportedName() {
|
||||
return exportedName;
|
||||
}
|
||||
|
||||
public void setExportedName(String name) {
|
||||
exportedName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> objectMap = (Map<String, Object>) objs.get("operations");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<CodegenOperation> operations = (List<CodegenOperation>) objectMap.get("operation");
|
||||
for (CodegenOperation operation : operations) {
|
||||
operation.httpMethod = operation.httpMethod.toLowerCase(Locale.ROOT);
|
||||
|
||||
List<CodegenParameter> params = operation.allParams;
|
||||
if (params != null && params.size() == 0) {
|
||||
operation.allParams = null;
|
||||
}
|
||||
List<CodegenResponse> responses = operation.responses;
|
||||
if (responses != null) {
|
||||
for (CodegenResponse resp : responses) {
|
||||
if ("0".equals(resp.code)) {
|
||||
resp.code = "default";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (operation.examples != null && !operation.examples.isEmpty()) {
|
||||
// Leave application/json* items only
|
||||
for (Iterator<Map<String, String>> it = operation.examples.iterator(); it.hasNext(); ) {
|
||||
final Map<String, String> example = it.next();
|
||||
final String contentType = example.get("contentType");
|
||||
if (contentType == null || !contentType.startsWith("application/json")) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return objs;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static List<Map<String, Object>> getOperations(Map<String, Object> objs) {
|
||||
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
|
||||
Map<String, Object> apiInfo = (Map<String, Object>) objs.get("apiInfo");
|
||||
List<Map<String, Object>> apis = (List<Map<String, Object>>) apiInfo.get("apis");
|
||||
for (Map<String, Object> api : apis) {
|
||||
result.add((Map<String, Object>) api.get("operations"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<Map<String, Object>> sortOperationsByPath(List<CodegenOperation> ops) {
|
||||
Multimap<String, CodegenOperation> opsByPath = ArrayListMultimap.create();
|
||||
|
||||
for (CodegenOperation op : ops) {
|
||||
opsByPath.put(op.path, op);
|
||||
}
|
||||
|
||||
List<Map<String, Object>> opsByPathList = new ArrayList<Map<String, Object>>();
|
||||
for (Entry<String, Collection<CodegenOperation>> entry : opsByPath.asMap().entrySet()) {
|
||||
Map<String, Object> opsByPathEntry = new HashMap<String, Object>();
|
||||
opsByPathList.add(opsByPathEntry);
|
||||
opsByPathEntry.put("path", entry.getKey());
|
||||
opsByPathEntry.put("operation", entry.getValue());
|
||||
List<CodegenOperation> operationsForThisPath = Lists.newArrayList(entry.getValue());
|
||||
operationsForThisPath.get(operationsForThisPath.size() - 1).hasMore = false;
|
||||
if (opsByPathList.size() < opsByPath.asMap().size()) {
|
||||
opsByPathEntry.put("hasMore", "true");
|
||||
}
|
||||
}
|
||||
|
||||
return opsByPathList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processOpts() {
|
||||
super.processOpts();
|
||||
|
||||
if (additionalProperties.containsKey(EXPORTED_NAME)) {
|
||||
setExportedName((String) additionalProperties.get(EXPORTED_NAME));
|
||||
}
|
||||
|
||||
/*
|
||||
* Supporting Files. You can write single files for the generator with the
|
||||
* entire object tree available. If the input file has a suffix of `.mustache
|
||||
* it will be processed by the template engine. Otherwise, it will be copied
|
||||
*/
|
||||
// supportingFiles.add(new SupportingFile("controller.mustache",
|
||||
// "controllers",
|
||||
// "controller.js")
|
||||
// );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preprocessOpenAPI(OpenAPI openAPI) {
|
||||
URL url = URLPathUtils.getServerURL(openAPI);
|
||||
String host = URLPathUtils.getProtocolAndHost(url);
|
||||
String port = URLPathUtils.getPort(url, defaultServerPort) ;
|
||||
String basePath = url.getPath();
|
||||
|
||||
if (additionalProperties.containsKey(SERVER_PORT)) {
|
||||
port = additionalProperties.get(SERVER_PORT).toString();
|
||||
}
|
||||
this.additionalProperties.put(SERVER_PORT, port);
|
||||
|
||||
if (openAPI.getInfo() != null) {
|
||||
Info info = openAPI.getInfo();
|
||||
if (info.getTitle() != null) {
|
||||
// when info.title is defined, use it for projectName
|
||||
// used in package.json
|
||||
projectName = info.getTitle()
|
||||
.replaceAll("[^a-zA-Z0-9]", "-")
|
||||
.replaceAll("^[-]*", "")
|
||||
.replaceAll("[-]*$", "")
|
||||
.replaceAll("[-]{2,}", "-")
|
||||
.toLowerCase(Locale.ROOT);
|
||||
this.additionalProperties.put("projectName", projectName);
|
||||
}
|
||||
}
|
||||
|
||||
// need vendor extensions
|
||||
Paths paths = openAPI.getPaths();
|
||||
if (paths != null) {
|
||||
for (String pathname : paths.keySet()) {
|
||||
PathItem path = paths.get(pathname);
|
||||
Map<HttpMethod, Operation> operationMap = path.readOperationsMap();
|
||||
if (operationMap != null) {
|
||||
for (HttpMethod method : operationMap.keySet()) {
|
||||
Operation operation = operationMap.get(method);
|
||||
String tag = "default";
|
||||
if (operation.getTags() != null && operation.getTags().size() > 0) {
|
||||
tag = toApiName(operation.getTags().get(0));
|
||||
}
|
||||
if (operation.getOperationId() == null) {
|
||||
operation.setOperationId(getOrGenerateOperationId(operation, pathname, method.toString()));
|
||||
}
|
||||
// add x-openapi-router-controller
|
||||
if (operation.getExtensions() == null ||
|
||||
operation.getExtensions().get("x-openapi-router-controller") == null) {
|
||||
operation.addExtension("x-openapi-router-controller", sanitizeTag(tag) + "Controller");
|
||||
}
|
||||
// add x-openapi-router-service
|
||||
if (operation.getExtensions() == null ||
|
||||
operation.getExtensions().get("x-openapi-router-service") == null) {
|
||||
operation.addExtension("x-openapi-router-service", sanitizeTag(tag) + "Service");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
|
||||
generateYAMLSpecFile(objs);
|
||||
|
||||
for (Map<String, Object> operations : getOperations(objs)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
|
||||
|
||||
List<Map<String, Object>> opsByPathList = sortOperationsByPath(ops);
|
||||
operations.put("operationsByPath", opsByPathList);
|
||||
}
|
||||
return super.postProcessSupportingFileData(objs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String removeNonNameElementToCamelCase(String name) {
|
||||
return removeNonNameElementToCamelCase(name, "[-:;#]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapeUnsafeCharacters(String input) {
|
||||
return input.replace("*/", "*_/").replace("/*", "/_*");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapeQuotationMark(String input) {
|
||||
// remove " to avoid code injection
|
||||
return input.replace("\"", "");
|
||||
}
|
||||
}
|
@ -0,0 +1,794 @@
|
||||
/*
|
||||
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.openapitools.codegen.languages;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import io.swagger.v3.oas.models.*;
|
||||
import io.swagger.v3.oas.models.headers.Header;
|
||||
import io.swagger.v3.oas.models.media.*;
|
||||
import io.swagger.v3.oas.models.parameters.Parameter;
|
||||
import io.swagger.v3.oas.models.responses.ApiResponse;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openapitools.codegen.*;
|
||||
import org.openapitools.codegen.utils.ModelUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.capitalize;
|
||||
import static org.openapitools.codegen.utils.StringUtils.camelize;
|
||||
import static org.openapitools.codegen.utils.StringUtils.escape;
|
||||
import static org.openapitools.codegen.utils.StringUtils.underscore;
|
||||
|
||||
public class OCamlClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(OCamlClientCodegen.class);
|
||||
public static final String PACKAGE_NAME = "packageName";
|
||||
public static final String PACKAGE_VERSION = "packageVersion";
|
||||
|
||||
static final String X_MODEL_MODULE = "x-modelModule";
|
||||
|
||||
public static final String CO_HTTP = "cohttp";
|
||||
|
||||
protected String packageName = "openapi";
|
||||
protected String packageVersion = "1.0.0";
|
||||
protected String apiDocPath = "docs/";
|
||||
protected String modelDocPath = "docs/";
|
||||
protected String apiFolder = "src/apis";
|
||||
protected String modelFolder = "src/models";
|
||||
|
||||
private Map<String, List<String>> enumNames = new HashMap<>();
|
||||
private Map<String, Schema> enumHash = new HashMap<>();
|
||||
private Map<String, String> enumUniqNames;
|
||||
|
||||
public CodegenType getTag() {
|
||||
return CodegenType.CLIENT;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "ocaml";
|
||||
}
|
||||
|
||||
public String getHelp() {
|
||||
return "Generates an OCaml client library (beta).";
|
||||
}
|
||||
|
||||
public OCamlClientCodegen() {
|
||||
super();
|
||||
outputFolder = "generated-code/ocaml";
|
||||
modelTemplateFiles.put("model.mustache", ".ml");
|
||||
|
||||
// default HIDE_GENERATION_TIMESTAMP to true
|
||||
hideGenerationTimestamp = Boolean.TRUE;
|
||||
|
||||
embeddedTemplateDir = templateDir = "ocaml";
|
||||
|
||||
setReservedWordsLowerCase(
|
||||
Arrays.asList(
|
||||
"and", "as", "assert", "asr", "begin", "class",
|
||||
"constraint", "do", "done", "downto", "else", "end",
|
||||
"exception", "external", "false", "for ", "fun", "function",
|
||||
"functor", "if", "in", "include", "inherit", "initializer",
|
||||
"land", "lazy", "let", "lor", "lsl", "lsr",
|
||||
"lxor", "match", "method", "mod", "module", "mutable",
|
||||
"new", "nonrec", "object", "of", "open", "or",
|
||||
"private", "rec", "sig", "struct", "then", "to",
|
||||
"true", "try", "type", "val", "virtual", "when",
|
||||
"while", "with",
|
||||
|
||||
"result"
|
||||
)
|
||||
);
|
||||
|
||||
importMapping.remove("File");
|
||||
|
||||
supportingFiles.add(new SupportingFile("dune.mustache", "", "dune"));
|
||||
supportingFiles.add(new SupportingFile("dune-project.mustache", "", "dune-project"));
|
||||
supportingFiles.add(new SupportingFile("readme.mustache", "", "README.md"));
|
||||
|
||||
defaultIncludes = new HashSet<>(
|
||||
Arrays.asList(
|
||||
"int",
|
||||
"int32",
|
||||
"int64",
|
||||
"float",
|
||||
"bool",
|
||||
"char",
|
||||
"string",
|
||||
"list"
|
||||
)
|
||||
);
|
||||
|
||||
languageSpecificPrimitives = new HashSet<>(
|
||||
Arrays.asList(
|
||||
"int",
|
||||
"int32",
|
||||
"int64",
|
||||
"float",
|
||||
"bool",
|
||||
"char",
|
||||
"string",
|
||||
"bytes",
|
||||
"list",
|
||||
"Yojson.Safe.t"
|
||||
)
|
||||
);
|
||||
|
||||
instantiationTypes.clear();
|
||||
|
||||
typeMapping.clear();
|
||||
typeMapping.put("boolean", "bool");
|
||||
typeMapping.put("int", "int32");
|
||||
typeMapping.put("long", "int64");
|
||||
typeMapping.put("short", "int");
|
||||
typeMapping.put("char", "char");
|
||||
typeMapping.put("float", "float");
|
||||
typeMapping.put("double", "float");
|
||||
typeMapping.put("integer", "int32");
|
||||
typeMapping.put("number", "float");
|
||||
typeMapping.put("date", "string");
|
||||
typeMapping.put("object", "Yojson.Safe.t");
|
||||
typeMapping.put("any", "Yojson.Safe.t");
|
||||
typeMapping.put("file", "string");
|
||||
typeMapping.put("ByteArray", "string");
|
||||
// lib
|
||||
typeMapping.put("string", "string");
|
||||
typeMapping.put("UUID", "string");
|
||||
typeMapping.put("URI", "string");
|
||||
typeMapping.put("set", "`Set");
|
||||
typeMapping.put("passsword", "string");
|
||||
typeMapping.put("DateTime", "string");
|
||||
|
||||
// supportedLibraries.put(CO_HTTP, "HTTP client: CoHttp.");
|
||||
//
|
||||
// CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use.");
|
||||
// libraryOption.setEnum(supportedLibraries);
|
||||
// // set hyper as the default
|
||||
// libraryOption.setDefault(CO_HTTP);
|
||||
// cliOptions.add(libraryOption);
|
||||
// setLibrary(CO_HTTP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> postProcessAllModels(Map<String, Object> superobjs) {
|
||||
List<String> toRemove = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<String, Object> modelEntry : superobjs.entrySet()) {
|
||||
Map<String, Object> objs = (Map<String, Object>) modelEntry.getValue();
|
||||
// process enum in models
|
||||
List<Object> models = (List<Object>) objs.get("models");
|
||||
for (Object _mo : models) {
|
||||
Map<String, Object> mo = (Map<String, Object>) _mo;
|
||||
CodegenModel cm = (CodegenModel) mo.get("model");
|
||||
|
||||
// for enum model
|
||||
if (Boolean.TRUE.equals(cm.isEnum) && cm.allowableValues != null) {
|
||||
toRemove.add(modelEntry.getKey());
|
||||
} else {
|
||||
enrichPropertiesWithEnumDefaultValues(cm.getAllVars());
|
||||
enrichPropertiesWithEnumDefaultValues(cm.getReadOnlyVars());
|
||||
enrichPropertiesWithEnumDefaultValues(cm.getReadWriteVars());
|
||||
enrichPropertiesWithEnumDefaultValues(cm.getRequiredVars());
|
||||
enrichPropertiesWithEnumDefaultValues(cm.getOptionalVars());
|
||||
enrichPropertiesWithEnumDefaultValues(cm.getVars());
|
||||
enrichPropertiesWithEnumDefaultValues(cm.getParentVars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String keyToRemove : toRemove) {
|
||||
superobjs.remove(keyToRemove);
|
||||
}
|
||||
|
||||
return superobjs;
|
||||
|
||||
}
|
||||
|
||||
private void enrichPropertiesWithEnumDefaultValues(List<CodegenProperty> properties) {
|
||||
for (CodegenProperty property : properties) {
|
||||
if (property.get_enum() != null && property.get_enum().size() == 1) {
|
||||
String value = property.get_enum().get(0);
|
||||
property.defaultValue = ocamlizeEnumValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateDataTypeWithEnumForMap(CodegenProperty property) {
|
||||
CodegenProperty baseItem = property.items;
|
||||
while (baseItem != null && (Boolean.TRUE.equals(baseItem.isMapContainer)
|
||||
|| Boolean.TRUE.equals(baseItem.isListContainer))) {
|
||||
baseItem = baseItem.items;
|
||||
}
|
||||
|
||||
if (baseItem != null) {
|
||||
// set default value for variable with inner enum
|
||||
if (property.defaultValue != null) {
|
||||
property.defaultValue = property.defaultValue.replace(", " + property.items.baseType, ", " + toEnumName(property.items));
|
||||
}
|
||||
|
||||
updateCodegenPropertyEnum(property);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateDataTypeWithEnumForArray(CodegenProperty property) {
|
||||
CodegenProperty baseItem = property.items;
|
||||
while (baseItem != null && (Boolean.TRUE.equals(baseItem.isMapContainer)
|
||||
|| Boolean.TRUE.equals(baseItem.isListContainer))) {
|
||||
baseItem = baseItem.items;
|
||||
}
|
||||
if (baseItem != null) {
|
||||
// set default value for variable with inner enum
|
||||
if (property.defaultValue != null) {
|
||||
property.defaultValue = property.defaultValue.replace(baseItem.baseType, toEnumName(baseItem));
|
||||
}
|
||||
|
||||
updateCodegenPropertyEnum(property);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private String hashEnum(Schema schema) {
|
||||
return ((List<Object>) schema.getEnum()).stream().map(String::valueOf).collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
private boolean isEnumSchema(Schema schema) {
|
||||
return schema != null && schema.getEnum() != null && !schema.getEnum().isEmpty();
|
||||
}
|
||||
|
||||
private void collectEnumSchemas(String parentName, String sName, Schema schema) {
|
||||
if (schema instanceof ArraySchema) {
|
||||
collectEnumSchemas(parentName, sName, ((ArraySchema) schema).getItems());
|
||||
} else if (schema instanceof MapSchema && schema.getAdditionalProperties() instanceof Schema) {
|
||||
collectEnumSchemas(parentName, sName, (Schema) schema.getAdditionalProperties());
|
||||
} else if (isEnumSchema(schema)) {
|
||||
String h = hashEnum(schema);
|
||||
if (!enumHash.containsKey(h)) {
|
||||
enumHash.put(h, schema);
|
||||
enumNames.computeIfAbsent(h, k -> new ArrayList<>()).add(sName.toLowerCase(Locale.ROOT));
|
||||
if (parentName != null) {
|
||||
enumNames.get(h).add((parentName + "_" + sName).toLowerCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void collectEnumSchemas(String sName, Schema schema) {
|
||||
collectEnumSchemas(null, sName, schema);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void collectEnumSchemas(String parentName, Map<String, Schema> schemas) {
|
||||
for (String sName : schemas.keySet()) {
|
||||
Schema schema = schemas.get(sName);
|
||||
|
||||
collectEnumSchemas(parentName, sName, schema);
|
||||
|
||||
if (schema.getProperties() != null) {
|
||||
String pName = parentName != null ? parentName + "_" + sName : sName;
|
||||
collectEnumSchemas(pName, schema.getProperties());
|
||||
}
|
||||
|
||||
if (schema.getAdditionalProperties() != null && schema.getAdditionalProperties() instanceof Schema) {
|
||||
String pName = parentName != null ? parentName + "_" + sName : sName;
|
||||
collectEnumSchemas(pName, (Schema) schema.getAdditionalProperties());
|
||||
}
|
||||
|
||||
if (schema instanceof ArraySchema) {
|
||||
ArraySchema s = (ArraySchema) schema;
|
||||
if (s.getItems() != null) {
|
||||
String pName = parentName != null ? parentName + "_" + sName : sName;
|
||||
collectEnumSchemas(pName, s.getItems());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void collectEnumSchemas(Operation operation) {
|
||||
if (operation != null) {
|
||||
if (operation.getParameters() != null) {
|
||||
for (Parameter parameter : operation.getParameters()) {
|
||||
collectEnumSchemas(parameter.getName(), parameter.getSchema());
|
||||
}
|
||||
}
|
||||
if (operation.getRequestBody() != null && operation.getRequestBody().getContent() != null) {
|
||||
Content content = operation.getRequestBody().getContent();
|
||||
for (String p : content.keySet()) {
|
||||
collectEnumSchemas(p, content.get(p).getSchema());
|
||||
}
|
||||
}
|
||||
if (operation.getResponses() != null) {
|
||||
for (String s : operation.getResponses().keySet()) {
|
||||
ApiResponse apiResponse = operation.getResponses().get(s);
|
||||
if (apiResponse.getContent() != null) {
|
||||
Content content = apiResponse.getContent();
|
||||
for (String p : content.keySet()) {
|
||||
collectEnumSchemas(p, content.get(p).getSchema());
|
||||
}
|
||||
}
|
||||
if (apiResponse.getHeaders() != null) {
|
||||
Map<String, Header> headers = apiResponse.getHeaders();
|
||||
for (String h : headers.keySet()) {
|
||||
Header header = headers.get(h);
|
||||
collectEnumSchemas(h, header.getSchema());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String sanitizeOCamlTypeName(String name) {
|
||||
String typeName = name.replace("-", "_").replace(" ", "_").trim();
|
||||
int i = 0;
|
||||
char c;
|
||||
while (i < typeName.length() && (Character.isDigit(c = typeName.charAt(i)) || c == '_')) {
|
||||
i++;
|
||||
}
|
||||
|
||||
return typeName.substring(i);
|
||||
}
|
||||
|
||||
private void computeEnumUniqNames() {
|
||||
Map<String, String> definitiveNames = new HashMap<>();
|
||||
for (String h : enumNames.keySet()) {
|
||||
boolean hasDefName = false;
|
||||
List<String> nameCandidates = enumNames.get(h);
|
||||
for (String name : nameCandidates) {
|
||||
String candidate = sanitizeOCamlTypeName(name);
|
||||
if (!definitiveNames.containsKey(candidate) && !reservedWords.contains(candidate)) {
|
||||
definitiveNames.put(candidate, h);
|
||||
hasDefName = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasDefName) {
|
||||
int i = 0;
|
||||
String candidate;
|
||||
while (definitiveNames.containsKey(candidate = sanitizeOCamlTypeName(nameCandidates.get(0) + "_" + i))) {
|
||||
i++;
|
||||
}
|
||||
definitiveNames.put(candidate, h);
|
||||
}
|
||||
}
|
||||
|
||||
enumUniqNames = definitiveNames.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
|
||||
}
|
||||
|
||||
private void collectEnumSchemas(OpenAPI openAPI) {
|
||||
Components components = openAPI.getComponents();
|
||||
if (components != null && components.getSchemas() != null && !components.getSchemas().isEmpty()) {
|
||||
collectEnumSchemas(null, components.getSchemas());
|
||||
}
|
||||
|
||||
Paths paths = openAPI.getPaths();
|
||||
if (paths != null && !paths.isEmpty()) {
|
||||
for (String path : paths.keySet()) {
|
||||
PathItem item = paths.get(path);
|
||||
collectEnumSchemas(item.getGet());
|
||||
collectEnumSchemas(item.getPost());
|
||||
collectEnumSchemas(item.getPut());
|
||||
collectEnumSchemas(item.getDelete());
|
||||
collectEnumSchemas(item.getPatch());
|
||||
collectEnumSchemas(item.getOptions());
|
||||
collectEnumSchemas(item.getHead());
|
||||
collectEnumSchemas(item.getTrace());
|
||||
}
|
||||
}
|
||||
|
||||
computeEnumUniqNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preprocessOpenAPI(OpenAPI openAPI) {
|
||||
collectEnumSchemas(openAPI);
|
||||
|
||||
supportingFiles.add(new SupportingFile("lib.mustache", "", packageName + ".opam"));
|
||||
supportingFiles.add(new SupportingFile("support.mustache", "src/support", "request.ml"));
|
||||
supportingFiles.add(new SupportingFile("json.mustache", "src/support", "jsonSupport.ml"));
|
||||
supportingFiles.add(new SupportingFile("enums.mustache", "src/support", "enums.ml"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processOpts() {
|
||||
super.processOpts();
|
||||
|
||||
if (StringUtils.isEmpty(System.getenv("OCAML_POST_PROCESS_FILE"))) {
|
||||
LOGGER.info("Hint: Environment variable 'OCAML_POST_PROCESS_FILE' (optional) not defined. E.g. to format the source code, please try 'export OCAML_POST_PROCESS_FILE=\"ocamlformat -i --enable-outside-detected-project\"' (Linux/Mac)");
|
||||
LOGGER.info("Note: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
|
||||
} else if (!this.isEnablePostProcessFile()) {
|
||||
LOGGER.info("Warning: Environment variable 'OCAML_POST_PROCESS_FILE' is set but file post-processing is not enabled. To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) {
|
||||
setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME));
|
||||
} else {
|
||||
setPackageName("openapi");
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_VERSION)) {
|
||||
setPackageVersion((String) additionalProperties.get(CodegenConstants.PACKAGE_VERSION));
|
||||
} else {
|
||||
setPackageVersion("1.0.0");
|
||||
}
|
||||
|
||||
additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
|
||||
additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion);
|
||||
|
||||
additionalProperties.put("apiDocPath", apiDocPath);
|
||||
additionalProperties.put("modelDocPath", modelDocPath);
|
||||
|
||||
apiTemplateFiles.put("api-impl.mustache", ".ml");
|
||||
apiTemplateFiles.put("api-intf.mustache", ".mli");
|
||||
|
||||
modelPackage = packageName;
|
||||
apiPackage = packageName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapeReservedWord(String name) {
|
||||
if (this.reservedWordsMappings().containsKey(name)) {
|
||||
return this.reservedWordsMappings().get(name);
|
||||
}
|
||||
return '_' + name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apiFileFolder() {
|
||||
return (outputFolder + File.separator + apiFolder).replace("/", File.separator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String modelFileFolder() {
|
||||
return (outputFolder + File.separator + modelFolder).replace("/", File.separator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toVarName(String name) {
|
||||
// replace - with _ e.g. created-at => created_at
|
||||
name = sanitizeName(name.replaceAll("-", "_"));
|
||||
|
||||
// snake_case, e.g. PetId => pet_id
|
||||
name = underscore(name);
|
||||
|
||||
// for reserved word or word starting with number, append _
|
||||
if (isReservedWord(name))
|
||||
name = escapeReservedWord(name);
|
||||
|
||||
// for reserved word or word starting with number, append _
|
||||
if (name.matches("^\\d.*"))
|
||||
name = "var_" + name;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toParamName(String name) {
|
||||
return toVarName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toModelName(String name) {
|
||||
// camelize the model name
|
||||
// phone_number => PhoneNumber
|
||||
return capitalize(toModelFilename(name)) + ".t";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toModelFilename(String name) {
|
||||
|
||||
if (!Strings.isNullOrEmpty(modelNamePrefix)) {
|
||||
name = modelNamePrefix + "_" + name;
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(modelNameSuffix)) {
|
||||
name = name + "_" + modelNameSuffix;
|
||||
}
|
||||
|
||||
name = sanitizeName(name);
|
||||
|
||||
// model name cannot use reserved keyword, e.g. return
|
||||
if (isReservedWord(name)) {
|
||||
LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + ("model_" + name));
|
||||
name = "model_" + name; // e.g. return => ModelReturn (after camelize)
|
||||
}
|
||||
|
||||
// model name starts with number or _
|
||||
if (name.matches("^\\d.*|^_.*")) {
|
||||
LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + ("model_" + name));
|
||||
name = "model_" + name; // e.g. 200Response => Model200Response (after camelize)
|
||||
}
|
||||
|
||||
return underscore(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toApiFilename(final String name) {
|
||||
// replace - with _ e.g. created-at => created_at
|
||||
final String _name = name.replaceAll("-", "_");
|
||||
|
||||
// e.g. PetApi.ml => pet_api.ml
|
||||
return underscore(_name) + "_api";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apiDocFileFolder() {
|
||||
return (outputFolder + "/" + apiDocPath).replace('/', File.separatorChar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String modelDocFileFolder() {
|
||||
return (outputFolder + "/" + modelDocPath).replace('/', File.separatorChar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toModelDocFilename(String name) {
|
||||
return toModelName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toApiDocFilename(String name) {
|
||||
return toApiName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeDeclaration(Schema p) {
|
||||
if (ModelUtils.isArraySchema(p)) {
|
||||
ArraySchema ap = (ArraySchema) p;
|
||||
Schema inner = ap.getItems();
|
||||
if (inner == null) {
|
||||
LOGGER.warn(ap.getName() + "(array property) does not have a proper inner type defined.Default to string");
|
||||
inner = new StringSchema().description("TODO default missing array inner type to string");
|
||||
}
|
||||
return getTypeDeclaration(inner) + " list";
|
||||
} else if (ModelUtils.isMapSchema(p)) {
|
||||
Schema inner = ModelUtils.getAdditionalProperties(p);
|
||||
if (inner == null) {
|
||||
LOGGER.warn(p.getName() + "(map property) does not have a proper inner type defined. Default to string");
|
||||
inner = new StringSchema().description("TODO default missing map inner type to string");
|
||||
}
|
||||
String prefix = inner.getEnum() != null ? "Enums." : "";
|
||||
return "(string * " + prefix + getTypeDeclaration(inner) + ") list";
|
||||
} else if (p.getEnum() != null) {
|
||||
String h = hashEnum(p);
|
||||
return enumUniqNames.get(h);
|
||||
}
|
||||
|
||||
Schema referencedSchema = ModelUtils.getReferencedSchema(openAPI, p);
|
||||
if (referencedSchema != null && referencedSchema.getEnum() != null) {
|
||||
String h = hashEnum(referencedSchema);
|
||||
return "Enums." + enumUniqNames.get(h);
|
||||
}
|
||||
|
||||
// Not using the supertype invocation, because we want to UpperCamelize
|
||||
// the type.
|
||||
String schemaType = getSchemaType(p);
|
||||
if (typeMapping.containsKey(schemaType)) {
|
||||
return typeMapping.get(schemaType);
|
||||
}
|
||||
|
||||
if (typeMapping.containsValue(schemaType)) {
|
||||
return schemaType;
|
||||
}
|
||||
|
||||
if (languageSpecificPrimitives.contains(schemaType)) {
|
||||
return schemaType;
|
||||
}
|
||||
|
||||
return toModelName(schemaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSchemaType(Schema p) {
|
||||
String schemaType = super.getSchemaType(p);
|
||||
if (typeMapping.containsKey(schemaType)) {
|
||||
String type = typeMapping.get(schemaType);
|
||||
if (languageSpecificPrimitives.contains(type)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return capitalize(toModelFilename(schemaType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toOperationId(String operationId) {
|
||||
String sanitizedOperationId = sanitizeName(operationId);
|
||||
|
||||
// method name cannot use reserved keyword, e.g. return
|
||||
if (isReservedWord(sanitizedOperationId) || sanitizedOperationId.matches("^[0-9].*")) {
|
||||
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + underscore("call_" + operationId));
|
||||
sanitizedOperationId = "call_" + sanitizedOperationId;
|
||||
}
|
||||
|
||||
return underscore(sanitizedOperationId);
|
||||
}
|
||||
|
||||
private Map<String, Object> allowableValues(String valueString) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("values", buildEnumValues(valueString));
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> buildEnumValues(String valueString) {
|
||||
List<Map<String, Object>> result = new ArrayList<>();
|
||||
|
||||
for (String v : valueString.split(",")) {
|
||||
Map<String, Object> m = new HashMap<>();
|
||||
String value = v.isEmpty() ? "empty" : v;
|
||||
m.put("name", value);
|
||||
m.put("camlEnumValueName", ocamlizeEnumValue(value));
|
||||
result.add(m);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toEnumValueName(String name) {
|
||||
if (reservedWords.contains(name)) {
|
||||
return escapeReservedWord(name);
|
||||
} else if (((CharSequence) name).chars().anyMatch(character -> specialCharReplacements.keySet().contains("" + ((char) character)))) {
|
||||
return escape(name, specialCharReplacements, Collections.singletonList("_"), null);
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
private String ocamlizeEnumValue(String value) {
|
||||
String sanitizedValue =
|
||||
toEnumValueName(value.isEmpty() ? "empty" : value)
|
||||
.replace(" ", "_");
|
||||
|
||||
if (!sanitizedValue.matches("^[a-zA-Z_].*")) {
|
||||
sanitizedValue = "_" + sanitizedValue;
|
||||
}
|
||||
return "`" + capitalize(sanitizedValue);
|
||||
}
|
||||
|
||||
private CodegenModel buildEnumModel(String enumName, String values) {
|
||||
CodegenModel m = new CodegenModel();
|
||||
m.setAllowableValues(allowableValues(values));
|
||||
m.setName(enumName);
|
||||
m.setClassname(enumName);
|
||||
m.setDataType(enumName);
|
||||
String[] vals = values.split(",");
|
||||
if (vals.length == 1) {
|
||||
m.setDefaultValue(ocamlizeEnumValue(vals[0]));
|
||||
}
|
||||
m.isEnum = true;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
private Map<String, Object> buildEnumModelWrapper(String enumName, String values) {
|
||||
Map<String, Object> m = new HashMap<>();
|
||||
m.put("importPath", packageName + "." + enumName);
|
||||
m.put("model", buildEnumModel(enumName, values));
|
||||
return m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> objectMap = (Map<String, Object>) objs.get("operations");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<CodegenOperation> operations = (List<CodegenOperation>) objectMap.get("operation");
|
||||
for (CodegenOperation operation : operations) {
|
||||
// http method verb conversion, depending on client library (e.g. Hyper: PUT => Put, Reqwest: PUT => put)
|
||||
//if (CO_HTTP.equals(getLibrary())) {
|
||||
for (CodegenParameter param : operation.bodyParams) {
|
||||
if (param.isModel && param.dataType.endsWith(".t")) {
|
||||
param.vendorExtensions.put(X_MODEL_MODULE, param.dataType.substring(0, param.dataType.lastIndexOf('.')));
|
||||
}
|
||||
}
|
||||
|
||||
if ("Yojson.Safe.t".equals(operation.returnBaseType)) {
|
||||
operation.vendorExtensions.put("x-returnFreeFormObject", true);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> e : enumUniqNames.entrySet()) {
|
||||
allModels.add(buildEnumModelWrapper(e.getValue(), e.getKey()));
|
||||
}
|
||||
|
||||
enumUniqNames.clear();
|
||||
|
||||
return objs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean needToImport(String type) {
|
||||
return !defaultIncludes.contains(type)
|
||||
&& !languageSpecificPrimitives.contains(type);
|
||||
}
|
||||
|
||||
public void setPackageName(String packageName) {
|
||||
this.packageName = packageName;
|
||||
}
|
||||
|
||||
public void setPackageVersion(String packageVersion) {
|
||||
this.packageVersion = packageVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapeQuotationMark(String input) {
|
||||
// remove " to avoid code injection
|
||||
return input.replace("\"", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapeUnsafeCharacters(String input) {
|
||||
return input
|
||||
.replace("*)", "*_)")
|
||||
.replace("(*", "(_*")
|
||||
.replace("\"", "''");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toEnumName(CodegenProperty property) {
|
||||
String hash = String.join(",", property.get_enum());
|
||||
|
||||
if (enumUniqNames.containsKey(hash)) {
|
||||
return enumUniqNames.get(hash);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unreferenced enum " + hash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toDefaultValue(Schema p) {
|
||||
if (p.getDefault() != null) {
|
||||
if (p.getEnum() != null) {
|
||||
return ocamlizeEnumValue(p.getDefault().toString());
|
||||
}
|
||||
return p.getDefault().toString();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessFile(File file, String fileType) {
|
||||
super.postProcessFile(file, fileType);
|
||||
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
String ocamlPostProcessFile = System.getenv("OCAML_POST_PROCESS_FILE");
|
||||
if (StringUtils.isEmpty(ocamlPostProcessFile)) {
|
||||
return; // skip if OCAML_POST_PROCESS_FILE env variable is not defined
|
||||
}
|
||||
// only process files with ml or mli extension
|
||||
if ("ml".equals(FilenameUtils.getExtension(file.toString())) || "mli".equals(FilenameUtils.getExtension(file.toString()))) {
|
||||
String command = ocamlPostProcessFile + " " + file.toString();
|
||||
try {
|
||||
Process p = Runtime.getRuntime().exec(command);
|
||||
int exitValue = p.waitFor();
|
||||
if (exitValue != 0) {
|
||||
LOGGER.error("Error running the command ({}). Exit value: {}", command, exitValue);
|
||||
} else {
|
||||
LOGGER.info("Successfully executed: " + command);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Error running the command ({}). Exception: {}", command, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -42,7 +42,7 @@ public class OpenAPIYamlGenerator extends DefaultCodegen implements CodegenConfi
|
||||
super();
|
||||
embeddedTemplateDir = templateDir = "openapi-yaml";
|
||||
outputFolder = "generated-code/openapi-yaml";
|
||||
cliOptions.add(new CliOption(OUTPUT_NAME, "output filename"));
|
||||
cliOptions.add(CliOption.newString(OUTPUT_NAME, "Output filename").defaultValue(outputFile));
|
||||
supportingFiles.add(new SupportingFile("README.md", "", "README.md"));
|
||||
}
|
||||
|
||||
|
@ -406,7 +406,7 @@ public class PhpSymfonyServerCodegen extends AbstractPhpCodegen implements Codeg
|
||||
// Create a variable to display the correct return type in comments for interfaces
|
||||
if (op.returnType != null) {
|
||||
op.vendorExtensions.put("x-commentType", op.returnType);
|
||||
if (!op.returnTypeIsPrimitive) {
|
||||
if (op.returnContainer != null && op.returnContainer.equals("array")) {
|
||||
op.vendorExtensions.put("x-commentType", op.returnType + "[]");
|
||||
}
|
||||
} else {
|
||||
|
@ -16,14 +16,29 @@
|
||||
|
||||
package org.openapitools.codegen.languages;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.swagger.v3.oas.models.media.Schema;
|
||||
import org.openapitools.codegen.*;
|
||||
import org.openapitools.codegen.utils.ModelUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PythonClientExperimentalCodegen extends PythonClientCodegen {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PythonClientExperimentalCodegen.class);
|
||||
|
||||
public PythonClientExperimentalCodegen() {
|
||||
super();
|
||||
|
||||
supportingFiles.add(new SupportingFile("python-experimental/api_client.mustache", packagePath(), "api_client.py"));
|
||||
apiDocTemplateFiles.put("python-experimental/api_doc.mustache", ".md");
|
||||
apiTemplateFiles.put("python-experimental/api.mustache", ".py");
|
||||
modelDocTemplateFiles.put("python-experimental/model_doc.mustache", ".md");
|
||||
modelTemplateFiles.put("python-experimental/model.mustache", ".py");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -36,4 +51,108 @@ public class PythonClientExperimentalCodegen extends PythonClientCodegen {
|
||||
public String getName() {
|
||||
return "python-experimental";
|
||||
}
|
||||
|
||||
public String dateToString(Schema p, Date date, DateFormat dateFormatter, DateFormat dateTimeFormatter) {
|
||||
// converts a date into a date or date-time python string
|
||||
if (!(ModelUtils.isDateSchema(p) || ModelUtils.isDateTimeSchema(p))) {
|
||||
throw new RuntimeException("passed schema must be of type Date or DateTime");
|
||||
}
|
||||
if (ModelUtils.isDateSchema(p)) {
|
||||
return "dateutil_parser('" + dateFormatter.format(date) + "').date()";
|
||||
}
|
||||
return "dateutil_parser('" + dateTimeFormatter.format(date) + "')";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default value of the property
|
||||
* @param p OpenAPI property object
|
||||
* @return string presentation of the default value of the property
|
||||
*/
|
||||
@Override
|
||||
public String toDefaultValue(Schema p) {
|
||||
// if a variable has no default set and only has one allowed value
|
||||
// using enum of length == 1 we use that value. Server/client usage:
|
||||
// python servers: should only use default values for optional params
|
||||
// python clients: should only use default values for required params
|
||||
Object defaultObject = null;
|
||||
Boolean enumLengthOne = (p.getEnum() != null && p.getEnum().size() == 1);
|
||||
if (p.getDefault() != null) {
|
||||
defaultObject = p.getDefault();
|
||||
} else if (enumLengthOne) {
|
||||
defaultObject = p.getEnum().get(0);
|
||||
}
|
||||
|
||||
// convert datetime and date enums if they exist
|
||||
DateFormat iso8601Date = new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT);
|
||||
DateFormat iso8601DateTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ROOT);
|
||||
TimeZone utc = TimeZone.getTimeZone("UTC");
|
||||
iso8601Date.setTimeZone(utc);
|
||||
iso8601DateTime.setTimeZone(utc);
|
||||
|
||||
if (ModelUtils.isDateSchema(p) || ModelUtils.isDateTimeSchema(p)) {
|
||||
List<Object> currentEnum = p.getEnum();
|
||||
List<String> fixedEnum = new ArrayList<String>();
|
||||
String fixedValue = null;
|
||||
Date date = null;
|
||||
if (currentEnum != null && !currentEnum.isEmpty()) {
|
||||
for (Object enumItem : currentEnum) {
|
||||
date = (Date) enumItem;
|
||||
fixedValue = dateToString(p, date, iso8601Date, iso8601DateTime);
|
||||
fixedEnum.add(fixedValue);
|
||||
}
|
||||
p.setEnum(fixedEnum);
|
||||
}
|
||||
|
||||
// convert the example if it exists
|
||||
Object currentExample = p.getExample();
|
||||
if (currentExample != null) {
|
||||
date = (Date) currentExample;
|
||||
fixedValue = dateToString(p, date, iso8601Date, iso8601DateTime);
|
||||
fixedEnum.add(fixedValue);
|
||||
p.setExample(fixedValue);
|
||||
}
|
||||
|
||||
// fix defaultObject
|
||||
if (defaultObject != null) {
|
||||
date = (Date) defaultObject;
|
||||
fixedValue = dateToString(p, date, iso8601Date, iso8601DateTime);
|
||||
p.setDefault(fixedValue);
|
||||
defaultObject = fixedValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String defaultValue = null;
|
||||
if (ModelUtils.isStringSchema(p)) {
|
||||
defaultValue = defaultObject.toString();
|
||||
if (ModelUtils.isDateSchema(p) || ModelUtils.isDateTimeSchema(p)) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (!ModelUtils.isByteArraySchema(p) && !ModelUtils.isBinarySchema(p) && !ModelUtils.isFileSchema(p) && !ModelUtils.isUUIDSchema(p) && !ModelUtils.isEmailSchema(p) && !ModelUtils.isDateTimeSchema(p) && !ModelUtils.isDateSchema(p)) {
|
||||
if (Pattern.compile("\r\n|\r|\n").matcher((String) defaultValue).find()) {
|
||||
defaultValue = "'''" + defaultValue + "'''";
|
||||
} else {
|
||||
defaultValue = "'" + defaultValue + "'";
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
} else if (ModelUtils.isIntegerSchema(p) || ModelUtils.isNumberSchema(p) || ModelUtils.isBooleanSchema(p)) {
|
||||
defaultValue = String.valueOf(defaultObject);
|
||||
if (ModelUtils.isBooleanSchema(p)) {
|
||||
if (Boolean.valueOf(defaultValue) == false) {
|
||||
return "False";
|
||||
} else {
|
||||
return "True";
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
} else {
|
||||
return defaultObject.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -46,6 +46,8 @@ public class RubyClientCodegen extends AbstractRubyCodegen {
|
||||
public static final String GEM_DESCRIPTION = "gemDescription";
|
||||
public static final String GEM_AUTHOR = "gemAuthor";
|
||||
public static final String GEM_AUTHOR_EMAIL = "gemAuthorEmail";
|
||||
public static final String FARADAY = "faraday";
|
||||
public static final String TYPHOEUS = "typhoeus";
|
||||
|
||||
protected String gemName;
|
||||
protected String moduleName;
|
||||
@ -54,8 +56,8 @@ public class RubyClientCodegen extends AbstractRubyCodegen {
|
||||
protected String libFolder = "lib";
|
||||
protected String gemLicense = "unlicense";
|
||||
protected String gemRequiredRubyVersion = ">= 1.9";
|
||||
protected String gemHomepage = "http://org.openapitools";
|
||||
protected String gemSummary = "A ruby wrapper for the REST APIs";
|
||||
protected String gemHomepage = "https://openapitools.org";
|
||||
protected String gemSummary = "A Ruby SDK for the REST API";
|
||||
protected String gemDescription = "This gem maps to a REST API";
|
||||
protected String gemAuthor = "";
|
||||
protected String gemAuthorEmail = "";
|
||||
@ -141,6 +143,15 @@ public class RubyClientCodegen extends AbstractRubyCodegen {
|
||||
cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC).
|
||||
defaultValue(Boolean.TRUE.toString()));
|
||||
|
||||
supportedLibraries.put(FARADAY, "Faraday (https://github.com/lostisland/faraday) (Beta support)");
|
||||
supportedLibraries.put(TYPHOEUS, "Typhoeus >= 1.0.1 (https://github.com/typhoeus/typhoeus)");
|
||||
|
||||
CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY, "HTTP library template (sub-template) to use");
|
||||
libraryOption.setEnum(supportedLibraries);
|
||||
// set TYPHOEUS as the default
|
||||
libraryOption.setDefault(TYPHOEUS);
|
||||
cliOptions.add(libraryOption);
|
||||
setLibrary(TYPHOEUS);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -209,10 +220,8 @@ public class RubyClientCodegen extends AbstractRubyCodegen {
|
||||
setModelPackage("models");
|
||||
setApiPackage("api");
|
||||
|
||||
supportingFiles.add(new SupportingFile("gemspec.mustache", "", gemName + ".gemspec"));
|
||||
supportingFiles.add(new SupportingFile("gem.mustache", libFolder, gemName + ".rb"));
|
||||
String gemFolder = libFolder + File.separator + gemName;
|
||||
supportingFiles.add(new SupportingFile("api_client.mustache", gemFolder, "api_client.rb"));
|
||||
supportingFiles.add(new SupportingFile("api_error.mustache", gemFolder, "api_error.rb"));
|
||||
supportingFiles.add(new SupportingFile("configuration.mustache", gemFolder, "configuration.rb"));
|
||||
supportingFiles.add(new SupportingFile("version.mustache", gemFolder, "version.rb"));
|
||||
@ -221,9 +230,20 @@ public class RubyClientCodegen extends AbstractRubyCodegen {
|
||||
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
|
||||
supportingFiles.add(new SupportingFile("Rakefile.mustache", "", "Rakefile"));
|
||||
supportingFiles.add(new SupportingFile("Gemfile.mustache", "", "Gemfile"));
|
||||
supportingFiles.add(new SupportingFile("Gemfile.lock.mustache", "", "Gemfile.lock"));
|
||||
supportingFiles.add(new SupportingFile("rubocop.mustache", "", ".rubocop.yml"));
|
||||
supportingFiles.add(new SupportingFile("travis.mustache", "", ".travis.yml"));
|
||||
supportingFiles.add(new SupportingFile("gemspec.mustache", "", gemName + ".gemspec"));
|
||||
supportingFiles.add(new SupportingFile("configuration.mustache", gemFolder, "configuration.rb"));
|
||||
supportingFiles.add(new SupportingFile("api_client.mustache", gemFolder, "api_client.rb"));
|
||||
|
||||
if (TYPHOEUS.equals(getLibrary())) {
|
||||
// for Typhoeus
|
||||
} else if (FARADAY.equals(getLibrary())) {
|
||||
// for Faraday
|
||||
additionalProperties.put("isFaraday", Boolean.TRUE);
|
||||
} else {
|
||||
throw new RuntimeException("Invalid HTTP library " + getLibrary() + ". Only faraday, typhoeus are supported.");
|
||||
}
|
||||
|
||||
// test files should not be overwritten
|
||||
writeOptional(outputFolder, new SupportingFile("rspec.mustache", "", ".rspec"));
|
||||
|
@ -709,6 +709,9 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
consumesPlainText = true;
|
||||
} else if (isMimetypeWwwFormUrlEncoded(mediaType)) {
|
||||
additionalProperties.put("usesUrlEncodedForm", true);
|
||||
} else if (isMimetypeMultipartFormData(mediaType)) {
|
||||
op.vendorExtensions.put("consumesMultipart", true);
|
||||
additionalProperties.put("apiUsesMultipart", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -724,8 +727,8 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
} else {
|
||||
op.bodyParam.vendorExtensions.put("consumesJson", true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (CodegenParameter param : op.bodyParams) {
|
||||
processParam(param, op);
|
||||
|
||||
@ -789,6 +792,8 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
codegenParameter.isPrimitiveType = false;
|
||||
codegenParameter.isListContainer = false;
|
||||
codegenParameter.isString = false;
|
||||
codegenParameter.isByteArray = ModelUtils.isByteArraySchema(original_schema);
|
||||
|
||||
|
||||
// This is a model, so should only have an example if explicitly
|
||||
// defined.
|
||||
|
@ -69,6 +69,9 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
public static final String RETURN_SUCCESS_CODE = "returnSuccessCode";
|
||||
public static final String UNHANDLED_EXCEPTION_HANDLING = "unhandledException";
|
||||
|
||||
public static final String OPEN_BRACE = "{";
|
||||
public static final String CLOSE_BRACE = "}";
|
||||
|
||||
protected String title = "OpenAPI Spring";
|
||||
protected String configPackage = "org.openapitools.configuration";
|
||||
protected String basePackage = "org.openapitools";
|
||||
@ -103,7 +106,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
invokerPackage = "org.openapitools.api";
|
||||
artifactId = "openapi-spring";
|
||||
|
||||
// clioOptions default redifinition need to be updated
|
||||
// clioOptions default redefinition need to be updated
|
||||
updateOption(CodegenConstants.INVOKER_PACKAGE, this.getInvokerPackage());
|
||||
updateOption(CodegenConstants.ARTIFACT_ID, this.getArtifactId());
|
||||
updateOption(CodegenConstants.API_PACKAGE, apiPackage);
|
||||
@ -113,6 +116,8 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
|
||||
// spring uses the jackson lib
|
||||
additionalProperties.put("jackson", "true");
|
||||
additionalProperties.put("openbrace", OPEN_BRACE);
|
||||
additionalProperties.put("closebrace", CLOSE_BRACE);
|
||||
|
||||
cliOptions.add(new CliOption(TITLE, "server title name or client service name").defaultValue(title));
|
||||
cliOptions.add(new CliOption(CONFIG_PACKAGE, "configuration package for generated code").defaultValue(this.getConfigPackage()));
|
||||
@ -132,7 +137,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
cliOptions.add(CliOption.newBoolean(IMPLICIT_HEADERS, "Skip header parameters in the generated API methods using @ApiImplicitParams annotation.", implicitHeaders));
|
||||
cliOptions.add(CliOption.newBoolean(OPENAPI_DOCKET_CONFIG, "Generate Spring OpenAPI Docket configuration class.", openapiDocketConfig));
|
||||
cliOptions.add(CliOption.newBoolean(API_FIRST, "Generate the API from the OAI spec at server compile time (API first approach)", apiFirst));
|
||||
cliOptions.add(CliOption.newBoolean(USE_OPTIONAL,"Use Optional container for optional parameters", useOptional));
|
||||
cliOptions.add(CliOption.newBoolean(USE_OPTIONAL, "Use Optional container for optional parameters", useOptional));
|
||||
cliOptions.add(CliOption.newBoolean(HATEOAS, "Use Spring HATEOAS library to allow adding HATEOAS links", hateoas));
|
||||
cliOptions.add(CliOption.newBoolean(RETURN_SUCCESS_CODE, "Generated server returns 2xx code", returnSuccessCode));
|
||||
cliOptions.add(CliOption.newBoolean(UNHANDLED_EXCEPTION_HANDLING, "Declare operation methods to throw a generic exception and allow unhandled exceptions (useful for Spring `@ControllerAdvice` directives).", unhandledException));
|
||||
@ -172,7 +177,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
@Override
|
||||
public void processOpts() {
|
||||
|
||||
List<Pair<String,String>> configOptions = additionalProperties.entrySet().stream()
|
||||
List<Pair<String, String>> configOptions = additionalProperties.entrySet().stream()
|
||||
.filter(e -> !Arrays.asList(API_FIRST, "hideGenerationTimestamp").contains(e.getKey()))
|
||||
.filter(e -> cliOptions.stream().map(CliOption::getOpt).anyMatch(opt -> opt.equals(e.getKey())))
|
||||
.map(e -> Pair.of(e.getKey(), e.getValue().toString()))
|
||||
@ -220,7 +225,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
} else {
|
||||
additionalProperties.put(BASE_PACKAGE, basePackage);
|
||||
}
|
||||
|
||||
|
||||
if (additionalProperties.containsKey(VIRTUAL_SERVICE)) {
|
||||
this.setVirtualService(Boolean.valueOf(additionalProperties.get(VIRTUAL_SERVICE).toString()));
|
||||
}
|
||||
@ -248,7 +253,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(REACTIVE)) {
|
||||
if (!library.equals(SPRING_BOOT)) {
|
||||
if (!SPRING_BOOT.equals(library)) {
|
||||
throw new IllegalArgumentException("Currently, reactive option is only supported with Spring-boot");
|
||||
}
|
||||
this.setReactive(Boolean.valueOf(additionalProperties.get(REACTIVE).toString()));
|
||||
@ -287,7 +292,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
if (additionalProperties.containsKey(API_FIRST)) {
|
||||
this.setApiFirst(Boolean.valueOf(additionalProperties.get(API_FIRST).toString()));
|
||||
}
|
||||
|
||||
|
||||
if (additionalProperties.containsKey(HATEOAS)) {
|
||||
this.setHateoas(Boolean.valueOf(additionalProperties.get(HATEOAS).toString()));
|
||||
}
|
||||
@ -398,12 +403,15 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
apiTemplateFiles.put("apiDelegate.mustache", "Delegate.java");
|
||||
}
|
||||
|
||||
|
||||
if (this.java8) {
|
||||
additionalProperties.put("javaVersion", "1.8");
|
||||
additionalProperties.put("jdk8-default-interface", !this.skipDefaultInterface);
|
||||
if (!SPRING_CLOUD_LIBRARY.equals(library)) {
|
||||
additionalProperties.put("jdk8", true);
|
||||
if (SPRING_CLOUD_LIBRARY.equals(library)) {
|
||||
additionalProperties.put("jdk8-default-interface", false);
|
||||
} else {
|
||||
additionalProperties.put("jdk8-default-interface", !this.skipDefaultInterface);
|
||||
}
|
||||
additionalProperties.put("jdk8", true);
|
||||
if (this.async) {
|
||||
additionalProperties.put(RESPONSE_WRAPPER, "CompletableFuture");
|
||||
}
|
||||
@ -414,7 +422,8 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
additionalProperties.put(RESPONSE_WRAPPER, "Callable");
|
||||
}
|
||||
|
||||
if(!this.apiFirst && !this.reactive) {
|
||||
|
||||
if (!this.apiFirst && !this.reactive) {
|
||||
additionalProperties.put("useSpringfox", true);
|
||||
}
|
||||
|
||||
@ -458,7 +467,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
|
||||
@Override
|
||||
public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map<String, List<CodegenOperation>> operations) {
|
||||
if((library.equals(SPRING_BOOT) || library.equals(SPRING_MVC_LIBRARY)) && !useTags) {
|
||||
if ((library.equals(SPRING_BOOT) || library.equals(SPRING_MVC_LIBRARY)) && !useTags) {
|
||||
String basePath = resourcePath;
|
||||
if (basePath.startsWith("/")) {
|
||||
basePath = basePath.substring(1);
|
||||
@ -490,7 +499,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
}
|
||||
*/
|
||||
|
||||
if(!additionalProperties.containsKey(TITLE)) {
|
||||
if (!additionalProperties.containsKey(TITLE)) {
|
||||
// From the title, compute a reasonable name for the package and the API
|
||||
String title = openAPI.getInfo().getTitle();
|
||||
|
||||
@ -506,7 +515,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
additionalProperties.put(TITLE, this.title);
|
||||
}
|
||||
|
||||
if(!additionalProperties.containsKey(SERVER_PORT)) {
|
||||
if (!additionalProperties.containsKey(SERVER_PORT)) {
|
||||
URL url = URLPathUtils.getServerURL(openAPI);
|
||||
this.additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, 8080));
|
||||
}
|
||||
@ -578,7 +587,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
}
|
||||
});
|
||||
|
||||
if(implicitHeaders){
|
||||
if (implicitHeaders) {
|
||||
removeHeadersFromAllParams(operation.allParams);
|
||||
}
|
||||
}
|
||||
@ -589,12 +598,12 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
|
||||
private interface DataTypeAssigner {
|
||||
void setReturnType(String returnType);
|
||||
|
||||
void setReturnContainer(String returnContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param returnType The return type that needs to be converted
|
||||
* @param returnType The return type that needs to be converted
|
||||
* @param dataTypeAssigner An object that will assign the data to the respective fields in the model.
|
||||
*/
|
||||
private void doDataTypeAssignment(String returnType, DataTypeAssigner dataTypeAssigner) {
|
||||
@ -625,29 +634,30 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
/**
|
||||
* This method removes header parameters from the list of parameters and also
|
||||
* corrects last allParams hasMore state.
|
||||
*
|
||||
* @param allParams list of all parameters
|
||||
*/
|
||||
private void removeHeadersFromAllParams(List<CodegenParameter> allParams) {
|
||||
if(allParams.isEmpty()){
|
||||
if (allParams.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final ArrayList<CodegenParameter> copy = new ArrayList<>(allParams);
|
||||
allParams.clear();
|
||||
|
||||
for(CodegenParameter p : copy){
|
||||
if(!p.isHeaderParam){
|
||||
for (CodegenParameter p : copy) {
|
||||
if (!p.isHeaderParam) {
|
||||
allParams.add(p);
|
||||
}
|
||||
}
|
||||
if (!allParams.isEmpty()) {
|
||||
allParams.get(allParams.size()-1).hasMore =false;
|
||||
allParams.get(allParams.size() - 1).hasMore = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
|
||||
generateYAMLSpecFile(objs);
|
||||
if(library.equals(SPRING_CLOUD_LIBRARY)) {
|
||||
if (library.equals(SPRING_CLOUD_LIBRARY)) {
|
||||
List<CodegenSecurity> authMethods = (List<CodegenSecurity>) objs.get("authMethods");
|
||||
if (authMethods != null) {
|
||||
for (CodegenSecurity authMethod : authMethods) {
|
||||
@ -717,9 +727,13 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
return this.basePackage;
|
||||
}
|
||||
|
||||
public void setInterfaceOnly(boolean interfaceOnly) { this.interfaceOnly = interfaceOnly; }
|
||||
public void setInterfaceOnly(boolean interfaceOnly) {
|
||||
this.interfaceOnly = interfaceOnly;
|
||||
}
|
||||
|
||||
public void setDelegatePattern(boolean delegatePattern) { this.delegatePattern = delegatePattern; }
|
||||
public void setDelegatePattern(boolean delegatePattern) {
|
||||
this.delegatePattern = delegatePattern;
|
||||
}
|
||||
|
||||
public void setSingleContentTypes(boolean singleContentTypes) {
|
||||
this.singleContentTypes = singleContentTypes;
|
||||
@ -729,13 +743,21 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
|
||||
public void setJava8(boolean java8) { this.java8 = java8; }
|
||||
|
||||
public void setVirtualService(boolean virtualService) { this.virtualService = virtualService; }
|
||||
public void setVirtualService(boolean virtualService) {
|
||||
this.virtualService = virtualService;
|
||||
}
|
||||
|
||||
public void setAsync(boolean async) { this.async = async; }
|
||||
public void setAsync(boolean async) {
|
||||
this.async = async;
|
||||
}
|
||||
|
||||
public void setReactive(boolean reactive) { this.reactive = reactive; }
|
||||
public void setReactive(boolean reactive) {
|
||||
this.reactive = reactive;
|
||||
}
|
||||
|
||||
public void setResponseWrapper(String responseWrapper) { this.responseWrapper = responseWrapper; }
|
||||
public void setResponseWrapper(String responseWrapper) {
|
||||
this.responseWrapper = responseWrapper;
|
||||
}
|
||||
|
||||
public void setUseTags(boolean useTags) {
|
||||
this.useTags = useTags;
|
||||
@ -752,7 +774,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
public void setApiFirst(boolean apiFirst) {
|
||||
this.apiFirst = apiFirst;
|
||||
}
|
||||
|
||||
|
||||
public void setHateoas(boolean hateoas) {
|
||||
this.hateoas = hateoas;
|
||||
}
|
||||
@ -793,7 +815,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
||||
objs = super.postProcessModelsEnum(objs);
|
||||
|
||||
//Add imports for Jackson
|
||||
List<Map<String, String>> imports = (List<Map<String, String>>)objs.get("imports");
|
||||
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
|
||||
List<Object> models = (List<Object>) objs.get("models");
|
||||
for (Object _mo : models) {
|
||||
Map<String, Object> mo = (Map<String, Object>) _mo;
|
||||
|
@ -28,6 +28,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.capitalize;
|
||||
import static org.openapitools.codegen.utils.StringUtils.*;
|
||||
@ -48,6 +49,8 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
|
||||
public static final String MODEL_SUFFIX = "modelSuffix";
|
||||
public static final String MODEL_FILE_SUFFIX = "modelFileSuffix";
|
||||
public static final String FILE_NAMING = "fileNaming";
|
||||
public static final String STRING_ENUMS = "stringEnums";
|
||||
public static final String STRING_ENUMS_DESC = "Generate string enums instead of objects for enum values.";
|
||||
|
||||
protected String ngVersion = "7.0.0";
|
||||
protected String npmRepository = null;
|
||||
@ -56,6 +59,7 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
|
||||
protected String modelSuffix = "";
|
||||
protected String modelFileSuffix = "";
|
||||
protected String fileNaming = "camelCase";
|
||||
protected Boolean stringEnums = false;
|
||||
|
||||
private boolean taggedUnions = false;
|
||||
|
||||
@ -88,6 +92,7 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
|
||||
this.cliOptions.add(new CliOption(MODEL_SUFFIX, "The suffix of the generated model."));
|
||||
this.cliOptions.add(new CliOption(MODEL_FILE_SUFFIX, "The suffix of the file of the generated model (model<suffix>.ts)."));
|
||||
this.cliOptions.add(new CliOption(FILE_NAMING, "Naming convention for the output files: 'camelCase', 'kebab-case'.").defaultValue(this.fileNaming));
|
||||
this.cliOptions.add(new CliOption(STRING_ENUMS, STRING_ENUMS_DESC).defaultValue(String.valueOf(this.stringEnums)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -136,6 +141,15 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
|
||||
addNpmPackageGeneration(ngVersion);
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(STRING_ENUMS)) {
|
||||
setStringEnums(Boolean.valueOf(additionalProperties.get(STRING_ENUMS).toString()));
|
||||
additionalProperties.put("stringEnums", getStringEnums());
|
||||
if (getStringEnums()) {
|
||||
enumSuffix = "";
|
||||
classEnumSeparator = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(WITH_INTERFACES)) {
|
||||
boolean withInterfaces = Boolean.parseBoolean(additionalProperties.get(WITH_INTERFACES).toString());
|
||||
if (withInterfaces) {
|
||||
@ -151,8 +165,9 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
|
||||
if (!additionalProperties.containsKey(PROVIDED_IN_ROOT)) {
|
||||
additionalProperties.put(PROVIDED_IN_ROOT, true);
|
||||
} else {
|
||||
additionalProperties.put(PROVIDED_IN_ROOT, Boolean.valueOf(
|
||||
(String) additionalProperties.get(PROVIDED_IN_ROOT)));
|
||||
additionalProperties.put(PROVIDED_IN_ROOT, Boolean.parseBoolean(
|
||||
additionalProperties.get(PROVIDED_IN_ROOT).toString()
|
||||
));
|
||||
}
|
||||
} else {
|
||||
additionalProperties.put(PROVIDED_IN_ROOT, false);
|
||||
@ -271,6 +286,14 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
|
||||
return indexPackage.replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
public void setStringEnums(boolean value) {
|
||||
stringEnums = value;
|
||||
}
|
||||
|
||||
public Boolean getStringEnums() {
|
||||
return stringEnums;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataTypeFile(final String dataType) {
|
||||
return dataType != null && dataType.equals("Blob");
|
||||
@ -330,7 +353,11 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
|
||||
objs.put("apiFilename", getApiFilenameFromClassname(objs.get("classname").toString()));
|
||||
|
||||
List<CodegenOperation> ops = (List<CodegenOperation>) objs.get("operation");
|
||||
boolean hasSomeFormParams = false;
|
||||
for (CodegenOperation op : ops) {
|
||||
if (op.getHasFormParams()) {
|
||||
hasSomeFormParams = true;
|
||||
}
|
||||
if ((boolean) additionalProperties.get("useHttpClient")) {
|
||||
op.httpMethod = op.httpMethod.toLowerCase(Locale.ENGLISH);
|
||||
} else {
|
||||
@ -406,6 +433,8 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
|
||||
op.path = pathBuffer.toString();
|
||||
}
|
||||
|
||||
operations.put("hasSomeFormParams", hasSomeFormParams);
|
||||
|
||||
// Add additional filename information for model imports in the services
|
||||
List<Map<String, Object>> imports = (List<Map<String, Object>>) operations.get("imports");
|
||||
for (Map<String, Object> im : imports) {
|
||||
@ -458,12 +487,33 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
|
||||
}
|
||||
}
|
||||
// Add additional filename information for imports
|
||||
mo.put("tsImports", toTsImports(cm, cm.imports));
|
||||
Set<String> parsedImports = parseImports(cm);
|
||||
mo.put("tsImports", toTsImports(cm, parsedImports));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse imports
|
||||
*/
|
||||
private Set<String> parseImports(CodegenModel cm) {
|
||||
Set<String> newImports = new HashSet<String>();
|
||||
if (cm.imports.size() > 0) {
|
||||
for (String name : cm.imports) {
|
||||
if (name.indexOf(" | ") >= 0) {
|
||||
String[] parts = name.split(" \\| ");
|
||||
for (String s : parts) {
|
||||
newImports.add(s);
|
||||
}
|
||||
} else {
|
||||
newImports.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newImports;
|
||||
}
|
||||
|
||||
private List<Map<String, String>> toTsImports(CodegenModel cm, Set<String> imports) {
|
||||
List<Map<String, String>> tsImports = new ArrayList<>();
|
||||
for (String im : imports) {
|
||||
|
@ -50,9 +50,9 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
|
||||
outputFolder = "generated-code/typescript-fetch";
|
||||
embeddedTemplateDir = templateDir = "typescript-fetch";
|
||||
|
||||
this.apiPackage = "apis";
|
||||
this.apiPackage = "src" + File.separator +"apis";
|
||||
this.modelPackage = "src" + File.separator + "models";
|
||||
this.apiTemplateFiles.put("apis.mustache", ".ts");
|
||||
this.modelPackage = "models";
|
||||
this.modelTemplateFiles.put("models.mustache", ".ts");
|
||||
this.addExtraReservedWords();
|
||||
|
||||
@ -84,8 +84,8 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
|
||||
super.processOpts();
|
||||
additionalProperties.put("isOriginalModelPropertyNaming", getModelPropertyNaming().equals("original"));
|
||||
additionalProperties.put("modelPropertyNaming", getModelPropertyNaming());
|
||||
supportingFiles.add(new SupportingFile("index.mustache", "", "index.ts"));
|
||||
supportingFiles.add(new SupportingFile("runtime.mustache", "", "runtime.ts"));
|
||||
supportingFiles.add(new SupportingFile("index.mustache", "src", "index.ts"));
|
||||
supportingFiles.add(new SupportingFile("runtime.mustache", "src", "runtime.ts"));
|
||||
supportingFiles.add(new SupportingFile("tsconfig.mustache", "", "tsconfig.json"));
|
||||
supportingFiles.add(new SupportingFile("gitignore", "", ".gitignore"));
|
||||
|
||||
@ -188,6 +188,7 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
|
||||
//Files for building our lib
|
||||
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
|
||||
supportingFiles.add(new SupportingFile("package.mustache", "", "package.json"));
|
||||
supportingFiles.add(new SupportingFile("npmignore.mustache", "", ".npmignore"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -216,7 +217,7 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
|
||||
// models for a given operation.
|
||||
List<Map<String, Object>> imports = (List<Map<String, Object>>) operations.get("imports");
|
||||
for (Map<String, Object> im : imports) {
|
||||
im.put("className", im.get("import").toString().replace("models.", ""));
|
||||
im.put("className", im.get("import").toString().replace(modelPackage() + ".", ""));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
package org.openapitools.codegen.languages;
|
||||
|
||||
import io.swagger.v3.oas.models.media.Schema;
|
||||
import io.swagger.v3.parser.util.SchemaTypeUtil;
|
||||
import org.openapitools.codegen.*;
|
||||
import org.openapitools.codegen.utils.ModelUtils;
|
||||
import org.slf4j.Logger;
|
||||
@ -33,6 +32,7 @@ public class TypeScriptNodeClientCodegen extends AbstractTypeScriptClientCodegen
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TypeScriptNodeClientCodegen.class);
|
||||
|
||||
public static final String NPM_REPOSITORY = "npmRepository";
|
||||
private static final String DEFAULT_IMPORT_PREFIX = "./";
|
||||
|
||||
protected String npmRepository = null;
|
||||
protected String apiSuffix = "Api";
|
||||
@ -96,22 +96,37 @@ public class TypeScriptNodeClientCodegen extends AbstractTypeScriptClientCodegen
|
||||
if (name.length() == 0) {
|
||||
return "default" + apiSuffix;
|
||||
}
|
||||
if (importMapping.containsKey(name)) {
|
||||
return importMapping.get(name);
|
||||
}
|
||||
return camelize(name, true) + apiSuffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toApiImport(String name) {
|
||||
if (importMapping.containsKey(name)) {
|
||||
return importMapping.get(name);
|
||||
}
|
||||
|
||||
return apiPackage() + "/" + toApiFilename(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toModelFilename(String name) {
|
||||
return camelize(toModelName(name), true);
|
||||
if (importMapping.containsKey(name)) {
|
||||
return importMapping.get(name);
|
||||
}
|
||||
|
||||
return DEFAULT_IMPORT_PREFIX + camelize(toModelName(name), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toModelImport(String name) {
|
||||
return modelPackage() + "/" + toModelFilename(name);
|
||||
if (importMapping.containsKey(name)) {
|
||||
return importMapping.get(name);
|
||||
}
|
||||
|
||||
return modelPackage() + "/" + camelize(toModelName(name), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -187,24 +187,14 @@ public class ApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set HTTP client
|
||||
* Set HTTP client, which must never be null.
|
||||
*
|
||||
* @param newHttpClient An instance of OkHttpClient
|
||||
* @return Api Client
|
||||
* @throws NullPointerException when newHttpClient is null
|
||||
*/
|
||||
public ApiClient setHttpClient(OkHttpClient newHttpClient) {
|
||||
if(!httpClient.equals(newHttpClient)) {
|
||||
OkHttpClient.Builder builder = newHttpClient.newBuilder();
|
||||
Iterator<Interceptor> networkInterceptorIterator = httpClient.networkInterceptors().iterator();
|
||||
while(networkInterceptorIterator.hasNext()) {
|
||||
builder.addNetworkInterceptor(networkInterceptorIterator.next());
|
||||
}
|
||||
Iterator<Interceptor> interceptorIterator = httpClient.interceptors().iterator();
|
||||
while(interceptorIterator.hasNext()) {
|
||||
builder.addInterceptor(interceptorIterator.next());
|
||||
}
|
||||
this.httpClient = builder.build();
|
||||
}
|
||||
this.httpClient = Objects.requireNonNull(newHttpClient, "HttpClient must not be null!");
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -555,6 +555,16 @@ public class ApiClient {
|
||||
return isForm ? formParams : obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand path template with variables
|
||||
* @param pathTemplate path template with placeholders
|
||||
* @param variables variables to replace
|
||||
* @return path with placeholders replaced by variables
|
||||
*/
|
||||
public String expandPath(String pathTemplate, Map<String, Object> variables) {
|
||||
return restTemplate.getUriTemplateHandler().expand(pathTemplate, variables).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke API by sending HTTP request with the given options.
|
||||
*
|
||||
@ -619,9 +629,6 @@ public class ApiClient {
|
||||
if (responseEntity.getStatusCode() == HttpStatus.NO_CONTENT) {
|
||||
return null;
|
||||
} else if (responseEntity.getStatusCode().is2xxSuccessful()) {
|
||||
if (returnType == null) {
|
||||
return null;
|
||||
}
|
||||
return responseEntity.getBody();
|
||||
} else {
|
||||
// The error handler built into the RestTemplate should handle 400 and 500 series errors.
|
||||
|
@ -6,6 +6,7 @@ import {{invokerPackage}}.ApiClient;
|
||||
{{/imports}}
|
||||
|
||||
{{^fullJavaUtil}}import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -72,7 +73,7 @@ public class {{classname}} {
|
||||
// create path and map variables
|
||||
final Map<String, Object> uriVariables = new HashMap<String, Object>();{{#pathParams}}
|
||||
uriVariables.put("{{baseName}}", {{#collectionFormat}}apiClient.collectionPathParameterToString(ApiClient.CollectionFormat.valueOf("{{{collectionFormat}}}".toUpperCase()), {{{paramName}}}){{/collectionFormat}}{{^collectionFormat}}{{{paramName}}}{{/collectionFormat}});{{/pathParams}}{{/hasPathParams}}
|
||||
String path = UriComponentsBuilder.fromPath("{{{path}}}"){{#hasPathParams}}.buildAndExpand(uriVariables){{/hasPathParams}}{{^hasPathParams}}.build(){{/hasPathParams}}.toUriString();
|
||||
String path = apiClient.expandPath("{{{path}}}", {{#hasPathParams}}uriVariables{{/hasPathParams}}{{^hasPathParams}}Collections.<String, Object>emptyMap(){{/hasPathParams}});
|
||||
|
||||
final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
|
||||
final HttpHeaders headerParams = new HttpHeaders();
|
||||
|
@ -20,7 +20,8 @@ public class {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{{#parcela
|
||||
{{/isContainer}}
|
||||
{{/isEnum}}
|
||||
{{#jackson}}
|
||||
@JsonProperty("{{baseName}}")
|
||||
public static final String JSON_PROPERTY_{{nameInSnakeCase}} = "{{baseName}}";
|
||||
@JsonProperty(JSON_PROPERTY_{{nameInSnakeCase}})
|
||||
{{#withXml}}
|
||||
{{^isContainer}}
|
||||
@JacksonXmlProperty({{#isXmlAttribute}}isAttribute = true, {{/isXmlAttribute}}{{#xmlNamespace}}namespace="{{xmlNamespace}}", {{/xmlNamespace}}localName = "{{#xmlName}}{{xmlName}}{{/xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}")
|
||||
|
@ -16,10 +16,12 @@ public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#seriali
|
||||
{{/isContainer}}
|
||||
{{/isEnum}}
|
||||
{{#jackson}}
|
||||
@JsonProperty("{{baseName}}")
|
||||
public static final String JSON_PROPERTY_{{nameInSnakeCase}} = "{{baseName}}";
|
||||
@JsonProperty(JSON_PROPERTY_{{nameInSnakeCase}})
|
||||
{{/jackson}}
|
||||
{{#gson}}
|
||||
@SerializedName("{{baseName}}")
|
||||
public static final String SERIALIZED_NAME_{{nameInSnakeCase}} = "{{baseName}}";
|
||||
@SerializedName(SERIALIZED_NAME_{{nameInSnakeCase}})
|
||||
{{/gson}}
|
||||
{{#isContainer}}
|
||||
private {{{datatypeWithEnum}}} {{name}}{{#required}} = {{{defaultValue}}}{{/required}}{{^required}} = null{{/required}};
|
||||
|
@ -24,25 +24,25 @@ public class ClientConfiguration {
|
||||
|
||||
{{#authMethods}}
|
||||
{{#isBasic}}
|
||||
{{=<% %>=}}@Value("${<%title%>.security.<%name%>.username:}")<%={{ }}=%>
|
||||
@Value("${{openbrace}}{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.username:{{closebrace}}")
|
||||
private String {{{name}}}Username;
|
||||
|
||||
{{=<% %>=}}@Value("${<%title%>.security.<%name%>.password:}")<%={{ }}=%>
|
||||
@Value("${{openbrace}}{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.password:{{closebrace}}")
|
||||
private String {{{name}}}Password;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "{{{title}}}.security.{{{name}}}.username")
|
||||
@ConditionalOnProperty(name = "{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.username")
|
||||
public BasicAuthRequestInterceptor {{{name}}}RequestInterceptor() {
|
||||
return new BasicAuthRequestInterceptor(this.{{{name}}}Username, this.{{{name}}}Password);
|
||||
}
|
||||
|
||||
{{/isBasic}}
|
||||
{{#isApiKey}}
|
||||
{{=<% %>=}}@Value("${<%title%>.security.<%name%>.key:}")<%={{ }}=%>
|
||||
@Value("${{openbrace}}{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.key:{{closebrace}}")
|
||||
private String {{{name}}}Key;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "{{{title}}}.security.{{{name}}}.key")
|
||||
@ConditionalOnProperty(name = "{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.key")
|
||||
public ApiKeyRequestInterceptor {{{name}}}RequestInterceptor() {
|
||||
return new ApiKeyRequestInterceptor({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{{keyParamName}}}", this.{{{name}}}Key);
|
||||
}
|
||||
@ -50,15 +50,15 @@ public class ClientConfiguration {
|
||||
{{/isApiKey}}
|
||||
{{#isOAuth}}
|
||||
@Bean
|
||||
@ConditionalOnProperty("{{{title}}}.security.{{{name}}}.client-id")
|
||||
@ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.client-id")
|
||||
public OAuth2FeignRequestInterceptor {{{name}}}RequestInterceptor() {
|
||||
return new OAuth2FeignRequestInterceptor(new DefaultOAuth2ClientContext(), {{{name}}}ResourceDetails());
|
||||
}
|
||||
|
||||
{{#isCode}}
|
||||
@Bean
|
||||
@ConditionalOnProperty("{{{title}}}.security.{{{name}}}.client-id")
|
||||
@ConfigurationProperties("{{{title}}}.security.{{{name}}}")
|
||||
@ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.client-id")
|
||||
@ConfigurationProperties("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}")
|
||||
public AuthorizationCodeResourceDetails {{{name}}}ResourceDetails() {
|
||||
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
|
||||
details.setAccessTokenUri("{{{tokenUrl}}}");
|
||||
@ -69,8 +69,8 @@ public class ClientConfiguration {
|
||||
{{/isCode}}
|
||||
{{#isPassword}}
|
||||
@Bean
|
||||
@ConditionalOnProperty("{{{title}}}.security.{{{name}}}.client-id")
|
||||
@ConfigurationProperties("{{{title}}}.security.{{{name}}}")
|
||||
@ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.client-id")
|
||||
@ConfigurationProperties("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}")
|
||||
public ResourceOwnerPasswordResourceDetails {{{name}}}ResourceDetails() {
|
||||
ResourceOwnerPasswordResourceDetails details = new ResourceOwnerPasswordResourceDetails();
|
||||
details.setAccessTokenUri("{{{tokenUrl}}}");
|
||||
@ -80,8 +80,8 @@ public class ClientConfiguration {
|
||||
{{/isPassword}}
|
||||
{{#isApplication}}
|
||||
@Bean
|
||||
@ConditionalOnProperty("{{{title}}}.security.{{{name}}}.client-id")
|
||||
@ConfigurationProperties("{{{title}}}.security.{{{name}}}")
|
||||
@ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.client-id")
|
||||
@ConfigurationProperties("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}")
|
||||
public ClientCredentialsResourceDetails {{{name}}}ResourceDetails() {
|
||||
ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails();
|
||||
details.setAccessTokenUri("{{{tokenUrl}}}");
|
||||
@ -91,8 +91,8 @@ public class ClientConfiguration {
|
||||
{{/isApplication}}
|
||||
{{#isImplicit}}
|
||||
@Bean
|
||||
@ConditionalOnProperty("{{{title}}}.security.{{{name}}}.client-id")
|
||||
@ConfigurationProperties("{{{title}}}.security.{{{name}}}")
|
||||
@ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.client-id")
|
||||
@ConfigurationProperties("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}")
|
||||
public ImplicitResourceDetails {{{name}}}ResourceDetails() {
|
||||
ImplicitResourceDetails details = new ImplicitResourceDetails();
|
||||
details.setUserAuthorizationUri("{{{authorizationUrl}}}");
|
||||
|
@ -29,6 +29,7 @@
|
||||
<sourceDirectory>src/main/java</sourceDirectory>
|
||||
</build>
|
||||
|
||||
{{^parentOverridden}}
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@ -41,11 +42,14 @@
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
{{/parentOverridden}}
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
{{^parentOverridden}}
|
||||
<version>${swagger-core-version}</version>
|
||||
{{/parentOverridden}}
|
||||
</dependency>
|
||||
<!-- @Nullable annotation -->
|
||||
<dependency>
|
||||
@ -84,13 +88,17 @@
|
||||
<dependency>
|
||||
<groupId>com.github.joschi.jackson</groupId>
|
||||
<artifactId>jackson-datatype-threetenbp</artifactId>
|
||||
{{^parentOverridden}}
|
||||
<version>2.6.4</version>
|
||||
{{/parentOverridden}}
|
||||
</dependency>
|
||||
{{/threetenbp}}
|
||||
<dependency>
|
||||
<groupId>org.openapitools</groupId>
|
||||
<artifactId>jackson-databind-nullable</artifactId>
|
||||
{{^parentOverridden}}
|
||||
<version>0.1.0</version>
|
||||
{{/parentOverridden}}
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -104,5 +112,14 @@
|
||||
<artifactId>spring-boot-starter-hateoas</artifactId>
|
||||
</dependency>
|
||||
{{/hateoas}}
|
||||
{{#useBeanValidation}}
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
{{^parentOverridden}}
|
||||
<version>6.0.16.Final</version>
|
||||
{{/parentOverridden}}
|
||||
</dependency>
|
||||
{{/useBeanValidation}}
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -61,7 +61,9 @@ org.openapitools.codegen.languages.JMeterClientCodegen
|
||||
org.openapitools.codegen.languages.LuaClientCodegen
|
||||
org.openapitools.codegen.languages.MysqlSchemaCodegen
|
||||
org.openapitools.codegen.languages.NodeJSServerCodegen
|
||||
org.openapitools.codegen.languages.NodeJSExpressServerCodegen
|
||||
org.openapitools.codegen.languages.ObjcClientCodegen
|
||||
org.openapitools.codegen.languages.OCamlClientCodegen
|
||||
org.openapitools.codegen.languages.OpenAPIGenerator
|
||||
org.openapitools.codegen.languages.OpenAPIYamlGenerator
|
||||
org.openapitools.codegen.languages.PerlClientCodegen
|
||||
|
@ -60,7 +60,7 @@ namespace {{packageName}}
|
||||
|
||||
// Add framework services.
|
||||
services
|
||||
.AddMvc({{^useDefaultRoutng}}opts => opts.EnableEndpointRouting = false{{/useDefaultRoutng}})
|
||||
.AddMvc({{^useDefaultRouting}}opts => opts.EnableEndpointRouting = false{{/useDefaultRouting}})
|
||||
{{#compatibilityVersion}}
|
||||
.SetCompatibilityVersion(CompatibilityVersion.{{compatibilityVersion}})
|
||||
{{/compatibilityVersion}}
|
||||
@ -127,12 +127,12 @@ namespace {{packageName}}
|
||||
|
||||
//TODO: Or alternatively use the original Swagger contract that's included in the static files
|
||||
// c.SwaggerEndpoint("/openapi-original.json", "{{#appName}}{{{appName}}}{{/appName}}{{^appName}}{{packageName}}{{/appName}} Original");
|
||||
}){{/useSwashbuckle}};{{^useDefaultRoutng}}
|
||||
}){{/useSwashbuckle}};{{^useDefaultRouting}}
|
||||
app.UseRouting();
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
});{{/useDefaultRoutng}}
|
||||
});{{/useDefaultRouting}}
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
|
@ -40,9 +40,14 @@ namespace {{apiPackage}}
|
||||
[SwaggerOperation("{{operationId}}")]{{#responses}}{{#dataType}}
|
||||
[SwaggerResponse(statusCode: {{code}}, type: typeof({{&dataType}}), description: "{{message}}")]{{/dataType}}{{^dataType}}{{/dataType}}{{/responses}}{{/useSwashbuckle}}{{^useSwashbuckle}}{{#responses}}{{#dataType}}
|
||||
[ProducesResponseType(statusCode: {{code}}, type: typeof({{&dataType}}))]{{/dataType}}{{^dataType}}{{/dataType}}{{/responses}}{{/useSwashbuckle}}
|
||||
public {{operationModifier}} {{#operationResultTask}}{{#operationIsAsync}}async {{/operationIsAsync}}Task<{{/operationResultTask}}IActionResult{{#operationResultTask}}>{{/operationResultTask}} {{operationId}}({{#allParams}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{^generateBody}};{{/generateBody}}
|
||||
public {{operationModifier}} {{#operationResultTask}}{{#operationIsAsync}}async {{/operationIsAsync}}Task<{{/operationResultTask}}IActionResult{{#operationResultTask}}>{{/operationResultTask}} {{operationId}}({{#allParams}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{#hasMore}}{{^isCookieParam}}, {{/isCookieParam}}{{/hasMore}}{{/allParams}}){{^generateBody}};{{/generateBody}}
|
||||
{{#generateBody}}
|
||||
{ {{#responses}}
|
||||
{
|
||||
{{#cookieParams}}
|
||||
var {{paramName}} = Request.Cookies["{{paramName}}"];
|
||||
{{/cookieParams}}
|
||||
|
||||
{{#responses}}
|
||||
{{#dataType}}
|
||||
//TODO: Uncomment the next line to return response {{code}} or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode({{code}}, default({{&dataType}}));
|
||||
@ -50,7 +55,8 @@ namespace {{apiPackage}}
|
||||
{{^dataType}}
|
||||
//TODO: Uncomment the next line to return response {{code}} or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode({{code}});
|
||||
{{/dataType}}{{/responses}}
|
||||
{{/dataType}}
|
||||
{{/responses}}
|
||||
{{#returnType}}
|
||||
string exampleJson = null;
|
||||
{{#examples}}
|
||||
|
@ -5,7 +5,8 @@
|
||||
{{#description}}
|
||||
/// <value>{{{description}}}</value>
|
||||
{{/description}}
|
||||
{{#allowableValues}}{{#enumVars}}{{#-first}}{{#isString}}[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]{{/isString}}{{/-first}}{{/enumVars}}{{/allowableValues}}
|
||||
{{#allowableValues}}{{#enumVars}}{{#-first}}{{#isString}}[TypeConverter(typeof(CustomEnumConverter<{{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}>))]
|
||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]{{/isString}}{{/-first}}{{/enumVars}}{{/allowableValues}}
|
||||
public enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}
|
||||
{
|
||||
{{#allowableValues}}{{#enumVars}}
|
||||
|
@ -3,9 +3,11 @@ using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using {{packageName}}.Converters;
|
||||
|
||||
{{#models}}
|
||||
{{#model}}
|
||||
|
33
modules/openapi-generator/src/main/resources/aspnetcore/2.1/typeConverter.mustache
vendored
Normal file
33
modules/openapi-generator/src/main/resources/aspnetcore/2.1/typeConverter.mustache
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace {{packageName}}.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom string to enum converter
|
||||
/// </summary>
|
||||
public class CustomEnumConverter<T> : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
if (sourceType == typeof(string))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
var s = value as string;
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<T>(@"""" + value.ToString() + @"""");
|
||||
}
|
||||
}
|
||||
}
|
@ -416,18 +416,16 @@ build_request_path() {
|
||||
|
||||
local query_request_part=""
|
||||
|
||||
local count=0
|
||||
for qparam in "${query_params[@]}"; do
|
||||
if [[ "${operation_parameters[$qparam]}" == "" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Get the array of parameter values
|
||||
local parameter_value=""
|
||||
local parameter_values
|
||||
mapfile -t parameter_values < <(sed -e 's/'":::"'/\n/g' <<<"${operation_parameters[$qparam]}")
|
||||
|
||||
if [[ -n "${parameter_values[*]}" ]]; then
|
||||
if [[ $((count++)) -gt 0 ]]; then
|
||||
query_request_part+="&"
|
||||
fi
|
||||
fi
|
||||
{{#hasAuthMethods}}{{#authMethods}}{{#isApiKey}}{{#isKeyInQuery}}
|
||||
if [[ ${qparam} == "{{keyParamName}}" ]]; then
|
||||
if [[ -n "${parameter_values[*]}" ]]; then
|
||||
@ -508,6 +506,9 @@ build_request_path() {
|
||||
fi
|
||||
|
||||
if [[ -n "${parameter_value}" ]]; then
|
||||
if [[ -n "${query_request_part}" ]]; then
|
||||
query_request_part+="&"
|
||||
fi
|
||||
query_request_part+="${parameter_value}"
|
||||
fi
|
||||
|
||||
|
@ -70,7 +70,12 @@ void {{classname}}::{{operationIdSnakeCase}}_handler(const Pistache::Rest::Reque
|
||||
try {
|
||||
{{#hasBodyParam}}
|
||||
{{#bodyParam}}
|
||||
{{^isPrimitiveType}}
|
||||
nlohmann::json::parse(request.body()).get_to({{paramName}});
|
||||
{{/isPrimitiveType}}
|
||||
{{#isPrimitiveType}}
|
||||
{{paramName}} = request.body();
|
||||
{{/isPrimitiveType}}
|
||||
{{/bodyParam}}
|
||||
{{/hasBodyParam}}
|
||||
this->{{operationIdSnakeCase}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}{{#hasParams}}, {{/hasParams}}response);
|
||||
|
@ -265,16 +265,19 @@ std::shared_ptr<std::istream> ModelBase::fromBase64( const utility::string_t& en
|
||||
|
||||
int64_t ModelBase::int64_tFromJson(const web::json::value& val)
|
||||
{
|
||||
return val.as_number().to_int64();
|
||||
return val.is_null() ? std::numeric_limits<int64_t>::quiet_NaN() : val.as_number().to_int64();
|
||||
}
|
||||
|
||||
int32_t ModelBase::int32_tFromJson(const web::json::value& val)
|
||||
{
|
||||
return val.as_integer();
|
||||
return val.is_null() ? std::numeric_limits<int32_t>::quiet_NaN() : val.as_integer();
|
||||
}
|
||||
|
||||
float ModelBase::floatFromJson(const web::json::value& val)
|
||||
{
|
||||
return static_cast<float>(val.as_double());
|
||||
return val.is_null() ? std::numeric_limits<float>::quiet_NaN() : static_cast<float>(val.as_double());
|
||||
}
|
||||
|
||||
utility::string_t ModelBase::stringFromJson(const web::json::value& val)
|
||||
{
|
||||
return val.is_string() ? val.as_string() : utility::conversions::to_string_t("");
|
||||
@ -282,15 +285,15 @@ utility::string_t ModelBase::stringFromJson(const web::json::value& val)
|
||||
|
||||
utility::datetime ModelBase::dateFromJson(const web::json::value& val)
|
||||
{
|
||||
return utility::datetime::from_string(val.as_string(), utility::datetime::ISO_8601);
|
||||
return val.is_null() ? utility::datetime::from_string(L"NULL", utility::datetime::ISO_8601) : utility::datetime::from_string(val.as_string(), utility::datetime::ISO_8601);
|
||||
}
|
||||
bool ModelBase::boolFromJson(const web::json::value& val)
|
||||
{
|
||||
return val.as_bool();
|
||||
return val.is_null() ? false : val.as_bool();
|
||||
}
|
||||
double ModelBase::doubleFromJson(const web::json::value& val)
|
||||
{
|
||||
return val.as_double();
|
||||
return val.is_null() ? std::numeric_limits<double>::quiet_NaN(): val.as_double();
|
||||
}
|
||||
|
||||
int64_t ModelBase::int64_tFromHttpContent(std::shared_ptr<HttpContent> val)
|
||||
|
@ -270,6 +270,14 @@ namespace {{packageName}}.Client
|
||||
}
|
||||
}
|
||||
|
||||
if (configuration.DefaultHeaders != null)
|
||||
{
|
||||
foreach (var headerParam in configuration.DefaultHeaders)
|
||||
{
|
||||
request.AddHeader(headerParam.Key, headerParam.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.HeaderParameters != null)
|
||||
{
|
||||
foreach (var headerParam in options.HeaderParameters)
|
||||
|
@ -35,7 +35,7 @@ namespace {{packageName}}.Client
|
||||
#endregion Constants
|
||||
|
||||
#region Static Members
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Default creation of exceptions for a given method name and response object
|
||||
/// </summary>
|
||||
@ -65,7 +65,7 @@ namespace {{packageName}}.Client
|
||||
/// Example: http://localhost:3000/v1/
|
||||
/// </summary>
|
||||
private String _basePath;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the API key based on the authentication name.
|
||||
/// This is the key and value comprising the "secret" for acessing an API.
|
||||
@ -94,7 +94,7 @@ namespace {{packageName}}.Client
|
||||
{
|
||||
UserAgent = "{{#httpUserAgent}}{{.}}{{/httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{packageVersion}}/csharp{{/httpUserAgent}}";
|
||||
BasePath = "{{{basePath}}}";
|
||||
DefaultHeader = new {{^net35}}Concurrent{{/net35}}Dictionary<string, string>();
|
||||
DefaultHeaders = new {{^net35}}Concurrent{{/net35}}Dictionary<string, string>();
|
||||
ApiKey = new {{^net35}}Concurrent{{/net35}}Dictionary<string, string>();
|
||||
ApiKeyPrefix = new {{^net35}}Concurrent{{/net35}}Dictionary<string, string>();
|
||||
|
||||
@ -107,15 +107,15 @@ namespace {{packageName}}.Client
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("ReSharper", "VirtualMemberCallInConstructor")]
|
||||
public Configuration(
|
||||
IDictionary<string, string> defaultHeader,
|
||||
IDictionary<string, string> defaultHeaders,
|
||||
IDictionary<string, string> apiKey,
|
||||
IDictionary<string, string> apiKeyPrefix,
|
||||
string basePath = "{{{basePath}}}") : this()
|
||||
{
|
||||
if (string.{{^net35}}IsNullOrWhiteSpace{{/net35}}{{#net35}}IsNullOrEmpty{{/net35}}(basePath))
|
||||
throw new ArgumentException("The provided basePath is invalid.", "basePath");
|
||||
if (defaultHeader == null)
|
||||
throw new ArgumentNullException("defaultHeader");
|
||||
if (defaultHeaders == null)
|
||||
throw new ArgumentNullException("defaultHeaders");
|
||||
if (apiKey == null)
|
||||
throw new ArgumentNullException("apiKey");
|
||||
if (apiKeyPrefix == null)
|
||||
@ -123,9 +123,9 @@ namespace {{packageName}}.Client
|
||||
|
||||
BasePath = basePath;
|
||||
|
||||
foreach (var keyValuePair in defaultHeader)
|
||||
foreach (var keyValuePair in defaultHeaders)
|
||||
{
|
||||
DefaultHeader.Add(keyValuePair);
|
||||
DefaultHeaders.Add(keyValuePair);
|
||||
}
|
||||
|
||||
foreach (var keyValuePair in apiKey)
|
||||
@ -156,7 +156,23 @@ namespace {{packageName}}.Client
|
||||
/// <summary>
|
||||
/// Gets or sets the default header.
|
||||
/// </summary>
|
||||
public virtual IDictionary<string, string> DefaultHeader { get; set; }
|
||||
[Obsolete("Use DefaultHeaders instead.")]
|
||||
public virtual IDictionary<string, string> DefaultHeader
|
||||
{
|
||||
get
|
||||
{
|
||||
return DefaultHeaders;
|
||||
}
|
||||
set
|
||||
{
|
||||
DefaultHeaders = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default headers.
|
||||
/// </summary>
|
||||
public virtual IDictionary<string, string> DefaultHeaders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the HTTP timeout (milliseconds) of ApiClient. Default to 100000 milliseconds.
|
||||
@ -374,17 +390,17 @@ namespace {{packageName}}.Client
|
||||
|
||||
Dictionary<string, string> apiKey = first.ApiKey.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
Dictionary<string, string> apiKeyPrefix = first.ApiKeyPrefix.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
Dictionary<string, string> defaultHeader = first.DefaultHeader.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
Dictionary<string, string> defaultHeaders = first.DefaultHeaders.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
|
||||
foreach (var kvp in second.ApiKey) apiKey[kvp.Key] = kvp.Value;
|
||||
foreach (var kvp in second.ApiKeyPrefix) apiKeyPrefix[kvp.Key] = kvp.Value;
|
||||
foreach (var kvp in second.DefaultHeader) defaultHeader[kvp.Key] = kvp.Value;
|
||||
foreach (var kvp in second.DefaultHeaders) defaultHeaders[kvp.Key] = kvp.Value;
|
||||
|
||||
var config = new Configuration
|
||||
{
|
||||
ApiKey = apiKey,
|
||||
ApiKeyPrefix = apiKeyPrefix,
|
||||
DefaultHeader = defaultHeader,
|
||||
DefaultHeader = defaultHeaders,
|
||||
BasePath = second.BasePath ?? first.BasePath,
|
||||
Timeout = second.Timeout,
|
||||
UserAgent = second.UserAgent ?? first.UserAgent,
|
||||
|
@ -1,5 +1,6 @@
|
||||
{{>partial_header}}
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace {{packageName}}.Client
|
||||
@ -43,8 +44,15 @@ namespace {{packageName}}.Client
|
||||
/// Gets the default header.
|
||||
/// </summary>
|
||||
/// <value>Default header.</value>
|
||||
[Obsolete("Use DefaultHeaders instead.")]
|
||||
IDictionary<string, string> DefaultHeader { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default headers.
|
||||
/// </summary>
|
||||
/// <value>Default headers.</value>
|
||||
IDictionary<string, string> DefaultHeaders { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the temp folder path.
|
||||
/// </summary>
|
||||
|
@ -32,7 +32,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>{{#returnType}}{{returnType}}{{/returnType}}</returns>
|
||||
{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}} ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}} ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = default({{{dataType}}}){{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
|
||||
/// <summary>
|
||||
/// {{summary}}
|
||||
@ -43,7 +43,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>ApiResponse of {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Object(void){{/returnType}}</returns>
|
||||
ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}> {{operationId}}WithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}> {{operationId}}WithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = default({{{dataType}}}){{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
{{/operation}}
|
||||
#endregion Synchronous Operations
|
||||
{{#supportsAsync}}
|
||||
@ -58,7 +58,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>Task of {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}void{{/returnType}}</returns>
|
||||
{{#returnType}}System.Threading.Tasks.Task<{{{returnType}}}>{{/returnType}}{{^returnType}}System.Threading.Tasks.Task{{/returnType}} {{operationId}}Async ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
{{#returnType}}System.Threading.Tasks.Task<{{{returnType}}}>{{/returnType}}{{^returnType}}System.Threading.Tasks.Task{{/returnType}} {{operationId}}Async ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = default({{{dataType}}}){{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
|
||||
/// <summary>
|
||||
/// {{summary}}
|
||||
@ -69,7 +69,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>Task of ApiResponse{{#returnType}} ({{returnType}}){{/returnType}}</returns>
|
||||
System.Threading.Tasks.Task<ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}>> {{operationId}}AsyncWithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
System.Threading.Tasks.Task<ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}>> {{operationId}}AsyncWithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = default({{{dataType}}}){{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
{{/operation}}
|
||||
#endregion Asynchronous Operations
|
||||
{{/supportsAsync}}
|
||||
@ -190,7 +190,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>{{#returnType}}{{returnType}}{{/returnType}}</returns>
|
||||
public {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}} ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
public {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}} ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = default({{{dataType}}}){{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
{
|
||||
{{#returnType}}ApiResponse<{{{returnType}}}> localVarResponse = {{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
return localVarResponse.Data;{{/returnType}}{{^returnType}}{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});{{/returnType}}
|
||||
@ -202,7 +202,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>ApiResponse of {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Object(void){{/returnType}}</returns>
|
||||
public ApiResponse<{{#returnType}} {{{returnType}}} {{/returnType}}{{^returnType}}Object{{/returnType}}> {{operationId}}WithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
public ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}> {{operationId}}WithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = default({{{dataType}}}){{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
{
|
||||
{{#allParams}}
|
||||
{{#required}}
|
||||
@ -325,7 +325,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>Task of {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}void{{/returnType}}</returns>
|
||||
{{#returnType}}public async System.Threading.Tasks.Task<{{{returnType}}}>{{/returnType}}{{^returnType}}public async System.Threading.Tasks.Task{{/returnType}} {{operationId}}Async ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
{{#returnType}}public async System.Threading.Tasks.Task<{{{returnType}}}>{{/returnType}}{{^returnType}}public async System.Threading.Tasks.Task{{/returnType}} {{operationId}}Async ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = default({{{dataType}}}){{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
{
|
||||
{{#returnType}}ApiResponse<{{{returnType}}}> localVarResponse = await {{operationId}}AsyncWithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
return localVarResponse.Data;{{/returnType}}{{^returnType}}await {{operationId}}AsyncWithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});{{/returnType}}
|
||||
@ -338,7 +338,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>Task of ApiResponse{{#returnType}} ({{returnType}}){{/returnType}}</returns>
|
||||
public async System.Threading.Tasks.Task<ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}>> {{operationId}}AsyncWithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
public async System.Threading.Tasks.Task<ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}>> {{operationId}}AsyncWithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = default({{{dataType}}}){{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
{
|
||||
{{#allParams}}
|
||||
{{#required}}
|
||||
|
@ -74,9 +74,9 @@ import 'package:{{pubName}}/api.dart';
|
||||
{{/authMethods}}
|
||||
{{/hasAuthMethods}}
|
||||
|
||||
var api_instance = new {{classname}}();
|
||||
var api_instance = {{classname}}();
|
||||
{{#allParams}}
|
||||
var {{paramName}} = {{#isListContainer}}[{{/isListContainer}}{{#isBodyParam}}new {{dataType}}(){{/isBodyParam}}{{^isBodyParam}}{{{example}}}{{/isBodyParam}}{{#isListContainer}}]{{/isListContainer}}; // {{{dataType}}} | {{{description}}}
|
||||
var {{paramName}} = {{#isListContainer}}[{{/isListContainer}}{{#isBodyParam}}{{dataType}}(){{/isBodyParam}}{{^isBodyParam}}{{{example}}}{{/isBodyParam}}{{#isListContainer}}]{{/isListContainer}}; // {{{dataType}}} | {{{description}}}
|
||||
{{/allParams}}
|
||||
|
||||
try {
|
||||
|
@ -19,7 +19,7 @@ class {{classname}} {
|
||||
{{#allParams}}
|
||||
{{#required}}
|
||||
if({{paramName}} == null) {
|
||||
throw new ApiException(400, "Missing required param: {{paramName}}");
|
||||
throw ApiException(400, "Missing required param: {{paramName}}");
|
||||
}
|
||||
{{/required}}
|
||||
{{/allParams}}
|
||||
@ -51,7 +51,7 @@ class {{classname}} {
|
||||
|
||||
if(contentType.startsWith("multipart/form-data")) {
|
||||
bool hasFields = false;
|
||||
MultipartRequest mp = new MultipartRequest(null, null);
|
||||
MultipartRequest mp = MultipartRequest(null, null);
|
||||
{{#formParams}}
|
||||
{{^isFile}}
|
||||
if ({{paramName}} != null) {
|
||||
@ -89,7 +89,7 @@ class {{classname}} {
|
||||
authNames);
|
||||
|
||||
if(response.statusCode >= 400) {
|
||||
throw new ApiException(response.statusCode, _decodeBodyBytes(response));
|
||||
throw ApiException(response.statusCode, _decodeBodyBytes(response));
|
||||
} else if(response.body != null) {
|
||||
{{#isListContainer}}
|
||||
{{#returnType}}
|
||||
@ -99,7 +99,7 @@ class {{classname}} {
|
||||
{{^isListContainer}}
|
||||
{{#isMapContainer}}
|
||||
{{#returnType}}
|
||||
return new {{{returnType}}}.from(apiClient.deserialize(_decodeBodyBytes(response), '{{{returnType}}}'));
|
||||
return {{{returnType}}}.from(apiClient.deserialize(_decodeBodyBytes(response), '{{{returnType}}}'));
|
||||
{{/returnType}};
|
||||
{{/isMapContainer}}
|
||||
{{^isMapContainer}}
|
||||
|
@ -45,9 +45,9 @@ import 'package:{{pubName}}/api.dart';
|
||||
{{/authMethods}}
|
||||
{{/hasAuthMethods}}
|
||||
|
||||
var api_instance = new {{classname}}();
|
||||
var api_instance = {{classname}}();
|
||||
{{#allParams}}
|
||||
var {{paramName}} = {{#isListContainer}}[{{/isListContainer}}{{#isBodyParam}}new {{dataType}}(){{/isBodyParam}}{{^isBodyParam}}{{{example}}}{{/isBodyParam}}{{#isListContainer}}]{{/isListContainer}}; // {{{dataType}}} | {{{description}}}
|
||||
var {{paramName}} = {{#isListContainer}}[{{/isListContainer}}{{#isBodyParam}}{{dataType}}(){{/isBodyParam}}{{^isBodyParam}}{{{example}}}{{/isBodyParam}}{{#isListContainer}}]{{/isListContainer}}; // {{{dataType}}} | {{{description}}}
|
||||
{{/allParams}}
|
||||
|
||||
try {
|
||||
|
@ -5,7 +5,7 @@ import 'package:test/test.dart';
|
||||
|
||||
/// tests for {{classname}}
|
||||
void main() {
|
||||
var instance = new {{classname}}();
|
||||
var instance = {{classname}}();
|
||||
|
||||
group('tests for {{classname}}', () {
|
||||
{{#operation}}
|
||||
|
@ -36,7 +36,7 @@ class {{classname}} {
|
||||
{{name}} = {{complexType}}.mapFromJson(json['{{baseName}}']);
|
||||
{{/isMapContainer}}
|
||||
{{^isMapContainer}}
|
||||
{{name}} = new {{complexType}}.fromJson(json['{{baseName}}']);
|
||||
{{name}} = {{complexType}}.fromJson(json['{{baseName}}']);
|
||||
{{/isMapContainer}}
|
||||
{{/isListContainer}}
|
||||
{{/complexType}}
|
||||
@ -49,7 +49,12 @@ class {{classname}} {
|
||||
{{name}} = (json['{{baseName}}'] as Map).cast<String, {{items.datatype}}>();
|
||||
{{/isMapContainer}}
|
||||
{{^isMapContainer}}
|
||||
{{#isDouble}}
|
||||
{{name}} = json['{{baseName}}'].toDouble();
|
||||
{{/isDouble}}
|
||||
{{^isDouble}}
|
||||
{{name}} = json['{{baseName}}'];
|
||||
{{/isDouble}}
|
||||
{{/isMapContainer}}
|
||||
{{/isListContainer}}
|
||||
{{/complexType}}
|
||||
@ -81,13 +86,13 @@ class {{classname}} {
|
||||
}
|
||||
|
||||
static List<{{classname}}> listFromJson(List<dynamic> json) {
|
||||
return json == null ? new List<{{classname}}>() : json.map((value) => new {{classname}}.fromJson(value)).toList();
|
||||
return json == null ? List<{{classname}}>() : json.map((value) => {{classname}}.fromJson(value)).toList();
|
||||
}
|
||||
|
||||
static Map<String, {{classname}}> mapFromJson(Map<String, dynamic> json) {
|
||||
var map = new Map<String, {{classname}}>();
|
||||
var map = Map<String, {{classname}}>();
|
||||
if (json != null && json.isNotEmpty) {
|
||||
json.forEach((String key, dynamic value) => map[key] = new {{classname}}.fromJson(value));
|
||||
json.forEach((String key, dynamic value) => map[key] = {{classname}}.fromJson(value));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import 'package:test/test.dart';
|
||||
|
||||
// tests for {{classname}}
|
||||
void main() {
|
||||
var instance = new Pet();
|
||||
var instance = {{classname}}();
|
||||
|
||||
group('test {{classname}}', () {
|
||||
{{#vars}}
|
||||
|
72
modules/openapi-generator/src/main/resources/nodejs-express-server/README.mustache
vendored
Normal file
72
modules/openapi-generator/src/main/resources/nodejs-express-server/README.mustache
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
{{=<% %>=}}
|
||||
# OpenAPI Generated JavaScript/Express Server
|
||||
|
||||
## Overview
|
||||
This server was generated using the [OpenAPI Generator](https://openapi-generator.tech) project. The code generator, and it's generated code allows you to develop your system with an API-First attitude, where the API contract is the anchor and definer of your project, and your code and business-logic aims to complete and comply to the terms in the API contract.
|
||||
|
||||
### prerequisites
|
||||
- NodeJS >= 10.4
|
||||
- NPM >= 6.10.0
|
||||
|
||||
The code was written on a mac, so assuming all should work smoothly on Linux-based computers. However, there is no reason not to run this library on Windows-based machines. If you find an OS-related problem, please open an issue and it will be resolved.
|
||||
|
||||
### Running the server
|
||||
To run the server, run:
|
||||
|
||||
```
|
||||
npm start
|
||||
```
|
||||
### View and test the API
|
||||
You can see the API documentation, and check the available endpoints by going to http://localhost:3000/api-docs/. Endpoints that require security need to have security handlers configured before they can return a successful response. At this point they will return [ a response code of 401](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401).
|
||||
##### At this stage the server does not support document body sent in xml format. Forms will be supported in the near future.
|
||||
|
||||
### Node version and guidelines
|
||||
The code was written using Node version 10.6, and complies to the [Airbnb .eslint guiding rules](https://github.com/airbnb/javascript).
|
||||
|
||||
### Project Files
|
||||
#### Root Directory:
|
||||
In the root directory we have (besides package.json, config.js, and log files):
|
||||
- **logger.js** - where we define the logger for the project. The project uses winston, but the purpose of this file is to enable users to change and modify their own logger behavior.
|
||||
- **index.js** - This is the project's 'main' file, and from here we launch the application. This is a very short and concise file, and the idea behind launching from this short file is to allow use-cases of launching the server with different parameters (changing config and/or logger) without affecting the rest of the code.
|
||||
- **expressServer.js** - The core of the Express.js server. This is where the express server is initialized, together with the OpenAPI validator, OpenAPI UI, and other libraries needed to start our server. If we want to add external links, that's where they would go. Our project uses the [express-openapi-validator](https://www.npmjs.com/package/express-openapi-validator) library that acts as a first step in the routing process - requests that are directed to paths defined in the `openapi.yaml` file are caught by this process, and it's parameters and bodyContent are validated against the schema. A successful result of this validation will be a new 'openapi' object added to the request. If the path requested is not part of the openapi.yaml file, the validator ignores the request and passes it on, as is, down the flow of the Express server.
|
||||
|
||||
#### api/
|
||||
- **openapi.yaml** - This is the OpenAPI contract to which this server will comply. The file was generated using the codegen, and should contain everything needed to run the API Gateway - no references to external models/schemas.
|
||||
|
||||
#### utils/
|
||||
Currently a single file:
|
||||
|
||||
- **openapiRouter.js** - This is where the routing to our back-end code happens. If the request object includes an ```openapi``` object, it picks up the following values (that are part of the ```openapi.yaml``` file): 'x-openapi-router-controller', and 'x-openapi-router-service'. These variables are names of files/classes in the controllers and services directories respectively. The operationId of the request is also extracted. The operationId is a method in the controller and the service that was generated as part of the codegen process. The routing process sends the request and response objects to the controller, which will extract the expected variables from the request, and send it to be processed by the service, returning the response from the service to the caller.
|
||||
|
||||
#### controllers/
|
||||
After validating the request, and ensuring this belongs to our API gateway, we send the request to a `controller`, where the variables and parameters are extracted from the request and sent to the relevant `service` for processing. The `controller` handles the response from the `service` and builds the appropriate HTTP response to be sent back to the user.
|
||||
|
||||
- **index.js** - load all the controllers that were generated for this project, and export them to be used dynamically by the `openapiRouter.js`. If you would like to customize your controller, it is advised that you link to your controller here, and ensure that the codegen does not rewrite this file.
|
||||
|
||||
- **Controller.js** - The core processor of the generated controllers. The generated controllers are designed to be as slim and generic as possible, referencing to the `Controller.js` for the business logic of parsing the needed variables and arguments from the request, and for building the HTTP response which will be sent back. The `Controller.js` is a class with static methods.
|
||||
|
||||
- **{{x-openapi-router-controller}}.js** - auto-generated code, processing all the operations. The Controller is a class that is constructed with the service class it will be sending the request to. Every request defined by the `openapi.yaml` has an operationId. The operationId is the name of the method that will be called. Every method receives the request and response, and calls the `Controller.js` to process the request and response, adding the service method that should be called for the actual business-logic processing.
|
||||
|
||||
#### services/
|
||||
This is where the API Gateway ends, and the unique business-logic of your application kicks in. Every endpoint in the `openapi.yaml` has a variable 'x-openapi-router-service', which is the name of the service class that is generated. The operationID of the endpoint is the name of the method that will be called. The generated code provides a simple promise with a try/catch clause. A successful operation ends with a call to the generic `Service.js` to build a successful response (payload and response code), and a failure will call the generic `Service.js` to build a response with an error object and the relevant response code. It is recommended to have the services be generated automatically once, and after the initial build add methods manually.
|
||||
|
||||
- **index.js** - load all the services that were generated for this project, and export them to be used dynamically by the `openapiRouter.js`. If you would like to customize your service, it is advised that you link to your controller here, and ensure that the codegen does not rewrite this file.
|
||||
|
||||
- **Service.js** - A utility class, very simple and thin at this point, with two static methods for building a response object for successful and failed results in the service operation. The default response code is 200 for success and 500 for failure. It is recommended to send more accurate response codes and override these defaults when relevant.
|
||||
|
||||
- **{{x-openapi-router-service}}.js** - auto-generated code, providing a stub Promise for each operationId defined in the `openapi.yaml`. Each method receives the variables that were defined in the `openapi.yaml` file, and wraps a Promise in a try/catch clause. The Promise resolves both success and failure in a call to the `Service.js` utility class for building the appropriate response that will be sent back to the Controller and then to the caller of this endpoint.
|
||||
|
||||
#### tests/
|
||||
- **serverTests.js** - basic server validation tests, checking that the server is up, that a call to an endpoint within the scope of the `openapi.yaml` file returns 200, that a call to a path outside that scope returns 200 if it exists and a 404 if not.
|
||||
- **routingTests.js** - Runs through all the endpoints defined in the `openapi.yaml`, and constructs a dummy request to send to the server. Confirms that the response code is 200. At this point requests containing xml or formData fail - currently they are not supported in the router.
|
||||
- **additionalEndpointsTests.js** - A test file for all the endpoints that are defined outside the openapi.yaml scope. Confirms that these endpoints return a successful 200 response.
|
||||
|
||||
|
||||
Future tests should be written to ensure that the response of every request sent should conform to the structure defined in the `openapi.yaml`. This test will fail 100% initially, and the job of the development team will be to clear these tests.
|
||||
|
||||
|
||||
#### models/
|
||||
Currently a concept awaiting feedback. The idea is to have the objects defined in the openapi.yaml act as models which are passed between the different modules. This will conform the programmers to interact using defined objects, rather than loosley-defined JSON objects. Given the nature of JavaScript progrmmers, who want to work with their own bootstrapped parameters, this concept might not work. Keeping this here for future discussion and feedback.
|
||||
|
||||
|
||||
|
30
modules/openapi-generator/src/main/resources/nodejs-express-server/app.mustache
vendored
Normal file
30
modules/openapi-generator/src/main/resources/nodejs-express-server/app.mustache
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
const ExpressServer = require('./expressServer');
|
||||
const logger = require('./logger');
|
||||
// const swaggerRouter = require('./utils/swaggerRouter');
|
||||
|
||||
class App {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
async launch() {
|
||||
try {
|
||||
this.expressServer = new ExpressServer(this.config.URL_PORT, this.config.OPENAPI_YAML);
|
||||
// this.expressServer.app.use(swaggerRouter());
|
||||
await this.expressServer.launch();
|
||||
logger.info('Express server running');
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
await this.close();
|
||||
}
|
||||
}
|
||||
|
||||
async close() {
|
||||
if (this.expressServer !== undefined) {
|
||||
await this.expressServer.close();
|
||||
logger.info(`Server shut down on port ${this.config.URL_PORT}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = App;
|
12
modules/openapi-generator/src/main/resources/nodejs-express-server/config.mustache
vendored
Normal file
12
modules/openapi-generator/src/main/resources/nodejs-express-server/config.mustache
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
const path = require('path');
|
||||
|
||||
const config = {
|
||||
ROOT_DIR: __dirname,
|
||||
URL_PORT: 3000,
|
||||
URL_PATH: 'http://localhost',
|
||||
BASE_VERSION: 'v2',
|
||||
CONTROLLER_DIRECTORY: path.join(__dirname, 'controllers'),
|
||||
};
|
||||
config.OPENAPI_YAML = path.join(config.ROOT_DIR, 'api', 'openapi.yaml');
|
||||
config.FULL_PATH = `${config.URL_PATH}:${config.URL_PORT}/${config.BASE_VERSION}`;
|
||||
module.exports = config;
|
18
modules/openapi-generator/src/main/resources/nodejs-express-server/controller.mustache
vendored
Normal file
18
modules/openapi-generator/src/main/resources/nodejs-express-server/controller.mustache
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
const Controller = require('./Controller');
|
||||
|
||||
class {{{classname}}}Controller {
|
||||
constructor(Service) {
|
||||
this.service = Service;
|
||||
}
|
||||
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
async {{operationId}}(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.{{operationId}});
|
||||
}
|
||||
|
||||
{{/operation}}
|
||||
}
|
||||
|
||||
module.exports = {{classname}}Controller;
|
||||
{{/operations}}
|
@ -0,0 +1,72 @@
|
||||
const logger = require('../logger');
|
||||
|
||||
class Controller {
|
||||
static sendResponse(response, payload) {
|
||||
/**
|
||||
* The default response-code is 200. We want to allow to change that. in That case,
|
||||
* payload will be an object consisting of a code and a payload. If not customized
|
||||
* send 200 and the payload as received in this method.
|
||||
*/
|
||||
response.status(payload.code || 200);
|
||||
const responsePayload = payload.payload !== undefined ? payload.payload : payload;
|
||||
if (responsePayload instanceof Object) {
|
||||
response.json(responsePayload);
|
||||
} else {
|
||||
response.end(responsePayload);
|
||||
}
|
||||
}
|
||||
|
||||
static sendError(response, error) {
|
||||
response.status(error.code || 500);
|
||||
if (error.error instanceof Object) {
|
||||
response.json(error.error);
|
||||
} else {
|
||||
response.end(error.error || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
static collectFiles(request) {
|
||||
logger.info('Checking if files are expected in schema');
|
||||
if (request.openapi.schema.requestBody !== undefined) {
|
||||
const [contentType] = request.headers['content-type'].split(';');
|
||||
if (contentType === 'multipart/form-data') {
|
||||
const contentSchema = request.openapi.schema.requestBody.content[contentType].schema;
|
||||
Object.entries(contentSchema.properties).forEach(([name, property]) => {
|
||||
if (property.type === 'string' && ['binary', 'base64'].indexOf(property.format) > -1) {
|
||||
request.body[name] = request.files.find(file => file.fieldname === name);
|
||||
}
|
||||
});
|
||||
} else if (request.openapi.schema.requestBody.content[contentType] !== undefined
|
||||
&& request.files !== undefined) {
|
||||
[request.body] = request.files;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static collectRequestParams(request) {
|
||||
this.collectFiles(request);
|
||||
const requestParams = {};
|
||||
if (request.openapi.schema.requestBody !== undefined) {
|
||||
requestParams.body = request.body;
|
||||
}
|
||||
request.openapi.schema.parameters.forEach((param) => {
|
||||
if (param.in === 'path') {
|
||||
requestParams[param.name] = request.openapi.pathParams[param.name];
|
||||
} else if (param.in === 'query') {
|
||||
requestParams[param.name] = request.query[param.name];
|
||||
}
|
||||
});
|
||||
return requestParams;
|
||||
}
|
||||
|
||||
static async handleRequest(request, response, serviceOperation) {
|
||||
try {
|
||||
const serviceResponse = await serviceOperation(this.collectRequestParams(request));
|
||||
Controller.sendResponse(response, serviceResponse);
|
||||
} catch (error) {
|
||||
Controller.sendError(response, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Controller;
|
25
modules/openapi-generator/src/main/resources/nodejs-express-server/controllers/index.mustache
vendored
Normal file
25
modules/openapi-generator/src/main/resources/nodejs-express-server/controllers/index.mustache
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
{{#-first}}
|
||||
const {{classname}}Controller = require('./{{classname}}Controller');
|
||||
{{/-first}}
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
|
||||
module.exports = {
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
{{#-first}}
|
||||
{{classname}}Controller,
|
||||
{{/-first}}
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
};
|
72
modules/openapi-generator/src/main/resources/nodejs-express-server/controllers/test.mustache
vendored
Normal file
72
modules/openapi-generator/src/main/resources/nodejs-express-server/controllers/test.mustache
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
const Service = require('../services/Service');
|
||||
|
||||
const testItems = require('../tests/testFiles/testItems.json');
|
||||
|
||||
class TestService {
|
||||
static testGetController() {
|
||||
return new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse(
|
||||
testItems,
|
||||
200,
|
||||
));
|
||||
} catch (e) {
|
||||
const message = e.getMessage() || 'Could not get items. Server error';
|
||||
reject(Service.rejectResponse(message, 500));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
sendResponse(request, response) {
|
||||
response.status(200);
|
||||
const objectToReturn = {};
|
||||
Object.keys(request.swagger.paramValues).forEach((key) => {
|
||||
const val = request.swagger.paramValues[key];
|
||||
if (val instanceof Object) {
|
||||
objectToReturn[key] = val.originalname || val.name || val;
|
||||
} else {
|
||||
objectToReturn[key] = request.swagger.paramValues[key];
|
||||
}
|
||||
});
|
||||
response.json(objectToReturn);
|
||||
}
|
||||
|
||||
confirmRouteGetSingle(request, response) {
|
||||
this.sendResponse(request, response);
|
||||
}
|
||||
|
||||
confirmRouteGetMany(request, response) {
|
||||
this.sendResponse(request, response);
|
||||
}
|
||||
|
||||
confirmRoutePost(request, response) {
|
||||
this.sendResponse(request, response);
|
||||
}
|
||||
|
||||
confirmRoutePut(request, response) {
|
||||
this.sendResponse(request, response);
|
||||
}
|
||||
|
||||
async testGetController(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.testGetController);
|
||||
}
|
||||
|
||||
async testPostController(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.testPostController);
|
||||
}
|
||||
|
||||
async testPutController(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.testPutController);
|
||||
}
|
||||
|
||||
async testDeleteController(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.testDeleteController);
|
||||
}
|
||||
|
||||
async testFindByIdController(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.testFindByIdController);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TestController;
|
8
modules/openapi-generator/src/main/resources/nodejs-express-server/eslintrc.mustache
vendored
Normal file
8
modules/openapi-generator/src/main/resources/nodejs-express-server/eslintrc.mustache
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
// Use this file as a starting point for your project's .eslintrc.
|
||||
// Copy this file, and add rule overrides as needed.
|
||||
{
|
||||
"extends": "airbnb",
|
||||
"rules": {
|
||||
"no-console": "off"
|
||||
}
|
||||
}
|
93
modules/openapi-generator/src/main/resources/nodejs-express-server/expressServer.mustache
vendored
Normal file
93
modules/openapi-generator/src/main/resources/nodejs-express-server/expressServer.mustache
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
// const { Middleware } = require('swagger-express-middleware');
|
||||
const path = require('path');
|
||||
const swaggerUI = require('swagger-ui-express');
|
||||
const yamljs = require('yamljs');
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const bodyParser = require('body-parser');
|
||||
const { OpenApiValidator } = require('express-openapi-validator');
|
||||
const openapiRouter = require('./utils/openapiRouter');
|
||||
const logger = require('./logger');
|
||||
|
||||
class ExpressServer {
|
||||
constructor(port, openApiYaml) {
|
||||
this.port = port;
|
||||
this.app = express();
|
||||
this.openApiPath = openApiYaml;
|
||||
this.schema = yamljs.load(openApiYaml);
|
||||
this.setupMiddleware();
|
||||
}
|
||||
|
||||
setupMiddleware() {
|
||||
// this.setupAllowedMedia();
|
||||
this.app.use(cors());
|
||||
this.app.use(bodyParser.json());
|
||||
this.app.use(express.json());
|
||||
this.app.use(express.urlencoded({ extended: false }));
|
||||
this.app.use(cookieParser());
|
||||
this.app.use('/spec', express.static(path.join(__dirname, 'api')));
|
||||
this.app.get('/hello', (req, res) => res.send('Hello World. path: '+this.openApiPath));
|
||||
// this.app.get('/spec', express.static(this.openApiPath));
|
||||
this.app.use('/api-docs', swaggerUI.serve, swaggerUI.setup(this.schema));
|
||||
this.app.get('/login-redirect', (req, res) => {
|
||||
res.status(200);
|
||||
res.json(req.query);
|
||||
});
|
||||
this.app.get('/oauth2-redirect.html', (req, res) => {
|
||||
res.status(200);
|
||||
res.json(req.query);
|
||||
});
|
||||
new OpenApiValidator({
|
||||
apiSpecPath: this.openApiPath,
|
||||
}).install(this.app);
|
||||
this.app.use(openapiRouter());
|
||||
this.app.get('/', (req, res) => {
|
||||
res.status(200);
|
||||
res.end('Hello World');
|
||||
});
|
||||
}
|
||||
|
||||
addErrorHandler() {
|
||||
this.app.use('*', (req, res) => {
|
||||
res.status(404);
|
||||
res.send(JSON.stringify({ error: `path ${req.baseUrl} doesn't exist` }));
|
||||
});
|
||||
/**
|
||||
* suppressed eslint rule: The next variable is required here, even though it's not used.
|
||||
*
|
||||
** */
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
this.app.use((error, req, res, next) => {
|
||||
const errorResponse = error.error || error.errors || error.message || 'Unknown error';
|
||||
res.status(error.status || 500);
|
||||
res.type('json');
|
||||
res.json({ error: errorResponse });
|
||||
});
|
||||
}
|
||||
|
||||
async launch() {
|
||||
return new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
this.addErrorHandler();
|
||||
this.server = await this.app.listen(this.port, () => {
|
||||
console.log(`server running on port ${this.port}`);
|
||||
resolve(this.server);
|
||||
});
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async close() {
|
||||
if (this.server !== undefined) {
|
||||
await this.server.close();
|
||||
console.log(`Server on port ${this.port} shut down`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ExpressServer;
|
28
modules/openapi-generator/src/main/resources/nodejs-express-server/index.mustache
vendored
Normal file
28
modules/openapi-generator/src/main/resources/nodejs-express-server/index.mustache
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
const config = require('./config');
|
||||
const logger = require('./logger');
|
||||
const ExpressServer = require('./expressServer');
|
||||
// const App = require('./app');
|
||||
|
||||
// const app = new App(config);
|
||||
// app.launch()
|
||||
// .then(() => {
|
||||
// logger.info('Server launched');
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// logger.error('found error, shutting down server');
|
||||
// app.close()
|
||||
// .catch(closeError => logger.error(closeError))
|
||||
// .finally(() => logger.error(error));
|
||||
// });
|
||||
const launchServer = async () => {
|
||||
try {
|
||||
this.expressServer = new ExpressServer(config.URL_PORT, config.OPENAPI_YAML);
|
||||
await this.expressServer.launch();
|
||||
logger.info('Express server running');
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
await this.close();
|
||||
}
|
||||
};
|
||||
|
||||
launchServer().catch(e => logger.error(e));
|
17
modules/openapi-generator/src/main/resources/nodejs-express-server/logger.mustache
vendored
Normal file
17
modules/openapi-generator/src/main/resources/nodejs-express-server/logger.mustache
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
const winston = require('winston');
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.json(),
|
||||
defaultMeta: { service: 'user-service' },
|
||||
transports: [
|
||||
new winston.transports.File({ filename: 'error.log', level: 'error' }),
|
||||
new winston.transports.File({ filename: 'combined.log' }),
|
||||
],
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
logger.add(new winston.transports.Console({ format: winston.format.simple() }));
|
||||
}
|
||||
|
||||
module.exports = logger;
|
1
modules/openapi-generator/src/main/resources/nodejs-express-server/openapi.mustache
vendored
Normal file
1
modules/openapi-generator/src/main/resources/nodejs-express-server/openapi.mustache
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{{openapi-yaml}}}
|
46
modules/openapi-generator/src/main/resources/nodejs-express-server/package.mustache
vendored
Normal file
46
modules/openapi-generator/src/main/resources/nodejs-express-server/package.mustache
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "openapi-petstore",
|
||||
"version": "1.0.0",
|
||||
"description": "This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"prestart": "npm install",
|
||||
"start": "node index.js"
|
||||
},
|
||||
"keywords": [
|
||||
"openapi-generator",
|
||||
"openapi"
|
||||
],
|
||||
"license": "Unlicense",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"body-parser": "^1.19.0",
|
||||
"connect": "^3.2.0",
|
||||
"cookie-parser": "^1.4.4",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.16.4",
|
||||
"express-openapi-validator": "^1.0.0",
|
||||
"js-yaml": "^3.3.0",
|
||||
"jstoxml": "^1.5.0",
|
||||
"ono": "^5.0.1",
|
||||
"openapi-sampler": "^1.0.0-beta.15",
|
||||
"swagger-express-middleware": "^2.0.2",
|
||||
"swagger-tools": "^0.10.4",
|
||||
"swagger-ui-express": "^4.0.2",
|
||||
"winston": "^3.2.1",
|
||||
"yamljs": "^0.3.0",
|
||||
"mocha": "^6.1.4",
|
||||
"axios": "^0.19.0",
|
||||
"chai": "^4.2.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-airbnb-base": "^13.1.0",
|
||||
"eslint-plugin-import": "^2.17.2",
|
||||
"form-data": "^2.3.3"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"env": {
|
||||
"node": true
|
||||
}
|
||||
}
|
||||
}
|
45
modules/openapi-generator/src/main/resources/nodejs-express-server/service.mustache
vendored
Normal file
45
modules/openapi-generator/src/main/resources/nodejs-express-server/service.mustache
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
const Service = require('./Service');
|
||||
|
||||
class {{{classname}}}Service {
|
||||
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
/**
|
||||
{{#summary}}
|
||||
* {{{summary}}}
|
||||
{{/summary}}
|
||||
{{#notes}}
|
||||
* {{{notes}}}
|
||||
{{/notes}}
|
||||
*
|
||||
{{#allParams}}
|
||||
* {{paramName}} {{{dataType}}} {{{description}}}{{^required}} (optional){{/required}}
|
||||
{{/allParams}}
|
||||
{{^returnType}}
|
||||
* no response value expected for this operation
|
||||
{{/returnType}}
|
||||
{{#returnType}}
|
||||
* returns {{{returnType}}}
|
||||
{{/returnType}}
|
||||
**/
|
||||
static {{{operationId}}}({{#allParams}}{{#-first}}{ {{/-first}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{#-last}} }{{/-last}}{{/allParams}}) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
{{/operation}}
|
||||
}
|
||||
|
||||
module.exports = {{{classname}}}Service;
|
||||
{{/operations}}
|
11
modules/openapi-generator/src/main/resources/nodejs-express-server/services/Service.mustache
vendored
Normal file
11
modules/openapi-generator/src/main/resources/nodejs-express-server/services/Service.mustache
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
class Service {
|
||||
static rejectResponse(error, code = 500) {
|
||||
return { error, code };
|
||||
}
|
||||
|
||||
static successResponse(payload, code = 200) {
|
||||
return { payload, code };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Service;
|
25
modules/openapi-generator/src/main/resources/nodejs-express-server/services/index.mustache
vendored
Normal file
25
modules/openapi-generator/src/main/resources/nodejs-express-server/services/index.mustache
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
{{#-first}}
|
||||
const {{classname}}Service = require('./{{classname}}Service');
|
||||
{{/-first}}
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
|
||||
module.exports = {
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
{{#-first}}
|
||||
{{classname}}Service,
|
||||
{{/-first}}
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user