[Java][Spring] do webflux controllers the right way - #571

Closed
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master
Closed

[Java][Spring] do webflux controllers the right way#571
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master

Conversation

@ilya1st

@ilya1stilya1st commented Jul 16, 2018

Copy link
Copy Markdown

Hello, there is a problem with mustache templates for spring-boot-webflux reactive case.
ResponseEntity<Mono|Flux> is wrong way for this case.
Right way is to use @RestController annotation and return directly Flux or Mono objects from controllers.

Here is patchset to make generator do it right.

@ilya1stilya1st changed the title do webflux controllers the right waydo java spring webflux controllers the right wayJul 16, 2018
@jmini

Copy link
Copy Markdown
Member

Java Technical Committee:
@bbdouglas (2017/07) @JFCote (2017/08) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01)
(we should have a Spring Technical Committee)

cc @macjohnny

@cbornet

Copy link
Copy Markdown
Member

It’s better to return a ResponseEntity to give the possibility for the implementer to set the Http status code and headers

@ilya1st

Copy link
Copy Markdown
Author

@cbornet that is wrong way cause with ResponseEntity you have to set http status code only once, before data is fetched and computed(before you know them). And cannot change them to status you need. But you can set them with WebExchange e.g.

exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);

After you fetch your data. And this is more flexible way than using ResponseEntity and exception handlers

@macjohnny

macjohnny commented Jul 18, 2018

Copy link
Copy Markdown
Member

@ilya1st it might be helpful for reviewing to optimize the PR. could you please

@cbornet

Copy link
Copy Markdown
Member

@ilya1st I'm not saying that the current implementation is OK but that we should keep the ResponseEntity. So return Mono<ResponseEntity<Foo>> and Mono<ResponseEntity<Flux<Foo>>>
The ServerWebExchange could also be passed (you would have to put it in the method arguments) but it's not as handy as ResponseEntity.

@cbornet

cbornet commented Jul 18, 2018

Copy link
Copy Markdown
Member

Actually the ServerWebExchange is already passed (we use it for the examples). Which is a good thing since it's the layer that gives the most flexibility (you can force the payload with untyped/raw data, etc...)

@ilya1st

Copy link
Copy Markdown
Author

@macjohnny I've reset branch to commit with mustache fixes.
There are some diffuculties with generating sources cause I have to work on Windows 7 machine and git marks some files 755 there :)

@wing328

Copy link
Copy Markdown
Member

I've updated the Petstore samples via e5f222d. Let's see how it goes.

@cbornet

Copy link
Copy Markdown
Member

@wing328 Note that there are still changes required on this PR

@wing328

Copy link
Copy Markdown
Member

@cbornet thanks for the heads-up. I'm just trying to resolve the Shippable CI error. Let me update the samples one more time to see how it goes.

@wing328wing328 changed the title do java spring webflux controllers the right way[Java][Spring] do webflux controllers the right wayJul 31, 2018
@ilya1st

Copy link
Copy Markdown
Author

@cbornet We had to write our generator based on this generator class for our internal projects for webflux. There are some issues with wrong work of delegate methods and classes for example. There are to much issues to make PRs for them.

For webflux case code looks slack-baked. May be better idea for springboot webflux case write separate generator from scratch? For now templates are too overloaded with cases to prevent erros there.
I can do this job.

@dr4ke616dr4ke616 mentioned this pull request Aug 15, 2018
12 tasks
@IsaacDeLaRosa

Copy link
Copy Markdown

@cbornet Is support for Mono<ResponseEntity<Foo>> (or Flux) controllers coming soon? if so will these be the required params and the right way to use it?

import org.openapitools.codegen.config.CodegenConfigurator
import org.openapitools.codegen.DefaultGenerator
def swaggerSourceFile = 'ignoreThis'
def swaggerTargetFolder = 'src/generated/java'
task generateApi {
inputs.file("$projectDir/$swaggerSourceFile")
outputs.dir("$projectDir/$swaggerTargetFolder")
doLast {
def config = new CodegenConfigurator()
config.setInputSpec("file:///$projectDir/$swaggerSourceFile")
config.setOutputDir("$projectDir")
config.setGeneratorName('spring')
config.setAdditionalProperties([
'interfaceOnly' : 'true',
'reactive' : 'true',
'apiPackage' : 'ignoreThis',
'modelPackage' : 'ignoreThis',
'sourceFolder' : swaggerTargetFolder
])
new DefaultGenerator().opts(config.toClientOptInput()).generate()
}
}

@cbornet

Copy link
Copy Markdown
Member

@IsaacDeLaRosa see #913 . As for the gradle part, have you tried the gradle plugin ?

@cbornet

Copy link
Copy Markdown
Member

Workaround with the current templates : if you need to set the status code or the headers reactively, you can do so by setting them on the ServerWebExchange in the reactive body. Eg:

@OverridepublicResponseEntity<Mono<Void>> deletePet(LongpetId, StringapiKey, ServerWebExchangeexchange) {
Mono<Void> result = Mono.empty()
.doOnSuccess(it -> exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN))
.doOnSuccess(it -> exchange.getResponse().getHeaders().add("foo", "bar"))
.then();
returnResponseEntity.status(HttpStatus.OK).body(result);
}

@jrobison153

Copy link
Copy Markdown

Chiming in here in agreement with the OP. We've been looking at the generated Spring Web Reactive interfaces and the response type wrappings seem superfluous, this is using version openapi-generator:3.3.1. For an API that returns a collection of type Foo, we get a Java interface with the following response signature

Mono<ResponseEntity<Flux<Foo>>>

From all of our testing this behaves identically to Flux<Foo> from a reactive client's perspective. The additional Mono<ResponseEntity> adds additional code to each controller to add the type wrappings.

Is there a reason for this or can it be simplified to Flux<Foo> and Mono<Foo>. The ServerWebExchange is already present and gives all the control over the HTTP session needed. It seems the generated code could be simplified

@cbornet

Copy link
Copy Markdown
Member

The same about ResponseEntity could be said for the non-reactive generation. I agree that it could be an option not to wrap into ResponseEntity.

@jrobison153

Copy link
Copy Markdown

Thanks for the quick response @cbornet, is this something you would be willing to take a PR for? If so would you want it conditional on option or just outright make the generator always create Flux and Mono response types?

@cbornet

Copy link
Copy Markdown
Member

It shall be conditional with an option at least for backward compat. We can discuss on what should be the default. I don't know when I can find enough time for this...

@cbornet

cbornet commented Oct 24, 2018

Copy link
Copy Markdown
Member

I'm closing this PR as the webflux gen has been fixed in another one.
@jrobison153 please open another issue for the optional ResponseEntity.

@cbornetcbornet closed this Oct 24, 2018
@jrobison153

Copy link
Copy Markdown

will do, cheers

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@ilya1st@jmini@cbornet@macjohnny@wing328@IsaacDeLaRosa@jrobison153
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[Java][Spring] do webflux controllers the right way - #571

Closed
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master
Closed

[Java][Spring] do webflux controllers the right way#571
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master

Conversation

@ilya1st

@ilya1stilya1st commented Jul 16, 2018

Copy link
Copy Markdown

Hello, there is a problem with mustache templates for spring-boot-webflux reactive case.
ResponseEntity<Mono|Flux> is wrong way for this case.
Right way is to use @RestController annotation and return directly Flux or Mono objects from controllers.

Here is patchset to make generator do it right.

@ilya1stilya1st changed the title do webflux controllers the right waydo java spring webflux controllers the right wayJul 16, 2018
@jmini

Copy link
Copy Markdown
Member

Java Technical Committee:
@bbdouglas (2017/07) @JFCote (2017/08) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01)
(we should have a Spring Technical Committee)

cc @macjohnny

@cbornet

Copy link
Copy Markdown
Member

It’s better to return a ResponseEntity to give the possibility for the implementer to set the Http status code and headers

@ilya1st

Copy link
Copy Markdown
Author

@cbornet that is wrong way cause with ResponseEntity you have to set http status code only once, before data is fetched and computed(before you know them). And cannot change them to status you need. But you can set them with WebExchange e.g.

exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);

After you fetch your data. And this is more flexible way than using ResponseEntity and exception handlers

@macjohnny

macjohnny commented Jul 18, 2018

Copy link
Copy Markdown
Member

@ilya1st it might be helpful for reviewing to optimize the PR. could you please

@cbornet

Copy link
Copy Markdown
Member

@ilya1st I'm not saying that the current implementation is OK but that we should keep the ResponseEntity. So return Mono<ResponseEntity<Foo>> and Mono<ResponseEntity<Flux<Foo>>>
The ServerWebExchange could also be passed (you would have to put it in the method arguments) but it's not as handy as ResponseEntity.

@cbornet

cbornet commented Jul 18, 2018

Copy link
Copy Markdown
Member

Actually the ServerWebExchange is already passed (we use it for the examples). Which is a good thing since it's the layer that gives the most flexibility (you can force the payload with untyped/raw data, etc...)

@ilya1st

Copy link
Copy Markdown
Author

@macjohnny I've reset branch to commit with mustache fixes.
There are some diffuculties with generating sources cause I have to work on Windows 7 machine and git marks some files 755 there :)

@wing328

Copy link
Copy Markdown
Member

I've updated the Petstore samples via e5f222d. Let's see how it goes.

@cbornet

Copy link
Copy Markdown
Member

@wing328 Note that there are still changes required on this PR

@wing328

Copy link
Copy Markdown
Member

@cbornet thanks for the heads-up. I'm just trying to resolve the Shippable CI error. Let me update the samples one more time to see how it goes.

@wing328wing328 changed the title do java spring webflux controllers the right way[Java][Spring] do webflux controllers the right wayJul 31, 2018
@ilya1st

Copy link
Copy Markdown
Author

@cbornet We had to write our generator based on this generator class for our internal projects for webflux. There are some issues with wrong work of delegate methods and classes for example. There are to much issues to make PRs for them.

For webflux case code looks slack-baked. May be better idea for springboot webflux case write separate generator from scratch? For now templates are too overloaded with cases to prevent erros there.
I can do this job.

@dr4ke616dr4ke616 mentioned this pull request Aug 15, 2018
12 tasks
@IsaacDeLaRosa

Copy link
Copy Markdown

@cbornet Is support for Mono<ResponseEntity<Foo>> (or Flux) controllers coming soon? if so will these be the required params and the right way to use it?

import org.openapitools.codegen.config.CodegenConfigurator
import org.openapitools.codegen.DefaultGenerator
def swaggerSourceFile = 'ignoreThis'
def swaggerTargetFolder = 'src/generated/java'
task generateApi {
inputs.file("$projectDir/$swaggerSourceFile")
outputs.dir("$projectDir/$swaggerTargetFolder")
doLast {
def config = new CodegenConfigurator()
config.setInputSpec("file:///$projectDir/$swaggerSourceFile")
config.setOutputDir("$projectDir")
config.setGeneratorName('spring')
config.setAdditionalProperties([
'interfaceOnly' : 'true',
'reactive' : 'true',
'apiPackage' : 'ignoreThis',
'modelPackage' : 'ignoreThis',
'sourceFolder' : swaggerTargetFolder
])
new DefaultGenerator().opts(config.toClientOptInput()).generate()
}
}

@cbornet

Copy link
Copy Markdown
Member

@IsaacDeLaRosa see #913 . As for the gradle part, have you tried the gradle plugin ?

@cbornet

Copy link
Copy Markdown
Member

Workaround with the current templates : if you need to set the status code or the headers reactively, you can do so by setting them on the ServerWebExchange in the reactive body. Eg:

@OverridepublicResponseEntity<Mono<Void>> deletePet(LongpetId, StringapiKey, ServerWebExchangeexchange) {
Mono<Void> result = Mono.empty()
.doOnSuccess(it -> exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN))
.doOnSuccess(it -> exchange.getResponse().getHeaders().add("foo", "bar"))
.then();
returnResponseEntity.status(HttpStatus.OK).body(result);
}

@jrobison153

Copy link
Copy Markdown

Chiming in here in agreement with the OP. We've been looking at the generated Spring Web Reactive interfaces and the response type wrappings seem superfluous, this is using version openapi-generator:3.3.1. For an API that returns a collection of type Foo, we get a Java interface with the following response signature

Mono<ResponseEntity<Flux<Foo>>>

From all of our testing this behaves identically to Flux<Foo> from a reactive client's perspective. The additional Mono<ResponseEntity> adds additional code to each controller to add the type wrappings.

Is there a reason for this or can it be simplified to Flux<Foo> and Mono<Foo>. The ServerWebExchange is already present and gives all the control over the HTTP session needed. It seems the generated code could be simplified

@cbornet

Copy link
Copy Markdown
Member

The same about ResponseEntity could be said for the non-reactive generation. I agree that it could be an option not to wrap into ResponseEntity.

@jrobison153

Copy link
Copy Markdown

Thanks for the quick response @cbornet, is this something you would be willing to take a PR for? If so would you want it conditional on option or just outright make the generator always create Flux and Mono response types?

@cbornet

Copy link
Copy Markdown
Member

It shall be conditional with an option at least for backward compat. We can discuss on what should be the default. I don't know when I can find enough time for this...

@cbornet

cbornet commented Oct 24, 2018

Copy link
Copy Markdown
Member

I'm closing this PR as the webflux gen has been fixed in another one.
@jrobison153 please open another issue for the optional ResponseEntity.

@cbornetcbornet closed this Oct 24, 2018
@jrobison153

Copy link
Copy Markdown

will do, cheers

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@ilya1st@jmini@cbornet@macjohnny@wing328@IsaacDeLaRosa@jrobison153
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[Java][Spring] do webflux controllers the right way - #571

Closed
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master
Closed

[Java][Spring] do webflux controllers the right way#571
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master

Conversation

@ilya1st

@ilya1stilya1st commented Jul 16, 2018

Copy link
Copy Markdown

Hello, there is a problem with mustache templates for spring-boot-webflux reactive case.
ResponseEntity<Mono|Flux> is wrong way for this case.
Right way is to use @RestController annotation and return directly Flux or Mono objects from controllers.

Here is patchset to make generator do it right.

@ilya1stilya1st changed the title do webflux controllers the right waydo java spring webflux controllers the right wayJul 16, 2018
@jmini

Copy link
Copy Markdown
Member

Java Technical Committee:
@bbdouglas (2017/07) @JFCote (2017/08) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01)
(we should have a Spring Technical Committee)

cc @macjohnny

@cbornet

Copy link
Copy Markdown
Member

It’s better to return a ResponseEntity to give the possibility for the implementer to set the Http status code and headers

@ilya1st

Copy link
Copy Markdown
Author

@cbornet that is wrong way cause with ResponseEntity you have to set http status code only once, before data is fetched and computed(before you know them). And cannot change them to status you need. But you can set them with WebExchange e.g.

exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);

After you fetch your data. And this is more flexible way than using ResponseEntity and exception handlers

@macjohnny

macjohnny commented Jul 18, 2018

Copy link
Copy Markdown
Member

@ilya1st it might be helpful for reviewing to optimize the PR. could you please

@cbornet

Copy link
Copy Markdown
Member

@ilya1st I'm not saying that the current implementation is OK but that we should keep the ResponseEntity. So return Mono<ResponseEntity<Foo>> and Mono<ResponseEntity<Flux<Foo>>>
The ServerWebExchange could also be passed (you would have to put it in the method arguments) but it's not as handy as ResponseEntity.

@cbornet

cbornet commented Jul 18, 2018

Copy link
Copy Markdown
Member

Actually the ServerWebExchange is already passed (we use it for the examples). Which is a good thing since it's the layer that gives the most flexibility (you can force the payload with untyped/raw data, etc...)

@ilya1st

Copy link
Copy Markdown
Author

@macjohnny I've reset branch to commit with mustache fixes.
There are some diffuculties with generating sources cause I have to work on Windows 7 machine and git marks some files 755 there :)

@wing328

Copy link
Copy Markdown
Member

I've updated the Petstore samples via e5f222d. Let's see how it goes.

@cbornet

Copy link
Copy Markdown
Member

@wing328 Note that there are still changes required on this PR

@wing328

Copy link
Copy Markdown
Member

@cbornet thanks for the heads-up. I'm just trying to resolve the Shippable CI error. Let me update the samples one more time to see how it goes.

@wing328wing328 changed the title do java spring webflux controllers the right way[Java][Spring] do webflux controllers the right wayJul 31, 2018
@ilya1st

Copy link
Copy Markdown
Author

@cbornet We had to write our generator based on this generator class for our internal projects for webflux. There are some issues with wrong work of delegate methods and classes for example. There are to much issues to make PRs for them.

For webflux case code looks slack-baked. May be better idea for springboot webflux case write separate generator from scratch? For now templates are too overloaded with cases to prevent erros there.
I can do this job.

@dr4ke616dr4ke616 mentioned this pull request Aug 15, 2018
12 tasks
@IsaacDeLaRosa

Copy link
Copy Markdown

@cbornet Is support for Mono<ResponseEntity<Foo>> (or Flux) controllers coming soon? if so will these be the required params and the right way to use it?

import org.openapitools.codegen.config.CodegenConfigurator
import org.openapitools.codegen.DefaultGenerator
def swaggerSourceFile = 'ignoreThis'
def swaggerTargetFolder = 'src/generated/java'
task generateApi {
inputs.file("$projectDir/$swaggerSourceFile")
outputs.dir("$projectDir/$swaggerTargetFolder")
doLast {
def config = new CodegenConfigurator()
config.setInputSpec("file:///$projectDir/$swaggerSourceFile")
config.setOutputDir("$projectDir")
config.setGeneratorName('spring')
config.setAdditionalProperties([
'interfaceOnly' : 'true',
'reactive' : 'true',
'apiPackage' : 'ignoreThis',
'modelPackage' : 'ignoreThis',
'sourceFolder' : swaggerTargetFolder
])
new DefaultGenerator().opts(config.toClientOptInput()).generate()
}
}

@cbornet

Copy link
Copy Markdown
Member

@IsaacDeLaRosa see #913 . As for the gradle part, have you tried the gradle plugin ?

@cbornet

Copy link
Copy Markdown
Member

Workaround with the current templates : if you need to set the status code or the headers reactively, you can do so by setting them on the ServerWebExchange in the reactive body. Eg:

@OverridepublicResponseEntity<Mono<Void>> deletePet(LongpetId, StringapiKey, ServerWebExchangeexchange) {
Mono<Void> result = Mono.empty()
.doOnSuccess(it -> exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN))
.doOnSuccess(it -> exchange.getResponse().getHeaders().add("foo", "bar"))
.then();
returnResponseEntity.status(HttpStatus.OK).body(result);
}

@jrobison153

Copy link
Copy Markdown

Chiming in here in agreement with the OP. We've been looking at the generated Spring Web Reactive interfaces and the response type wrappings seem superfluous, this is using version openapi-generator:3.3.1. For an API that returns a collection of type Foo, we get a Java interface with the following response signature

Mono<ResponseEntity<Flux<Foo>>>

From all of our testing this behaves identically to Flux<Foo> from a reactive client's perspective. The additional Mono<ResponseEntity> adds additional code to each controller to add the type wrappings.

Is there a reason for this or can it be simplified to Flux<Foo> and Mono<Foo>. The ServerWebExchange is already present and gives all the control over the HTTP session needed. It seems the generated code could be simplified

@cbornet

Copy link
Copy Markdown
Member

The same about ResponseEntity could be said for the non-reactive generation. I agree that it could be an option not to wrap into ResponseEntity.

@jrobison153

Copy link
Copy Markdown

Thanks for the quick response @cbornet, is this something you would be willing to take a PR for? If so would you want it conditional on option or just outright make the generator always create Flux and Mono response types?

@cbornet

Copy link
Copy Markdown
Member

It shall be conditional with an option at least for backward compat. We can discuss on what should be the default. I don't know when I can find enough time for this...

@cbornet

cbornet commented Oct 24, 2018

Copy link
Copy Markdown
Member

I'm closing this PR as the webflux gen has been fixed in another one.
@jrobison153 please open another issue for the optional ResponseEntity.

@cbornetcbornet closed this Oct 24, 2018
@jrobison153

Copy link
Copy Markdown

will do, cheers

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@ilya1st@jmini@cbornet@macjohnny@wing328@IsaacDeLaRosa@jrobison153
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[Java][Spring] do webflux controllers the right way - #571

Closed
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master
Closed

[Java][Spring] do webflux controllers the right way#571
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master

Conversation

@ilya1st

@ilya1stilya1st commented Jul 16, 2018

Copy link
Copy Markdown

Hello, there is a problem with mustache templates for spring-boot-webflux reactive case.
ResponseEntity<Mono|Flux> is wrong way for this case.
Right way is to use @RestController annotation and return directly Flux or Mono objects from controllers.

Here is patchset to make generator do it right.

@ilya1stilya1st changed the title do webflux controllers the right waydo java spring webflux controllers the right wayJul 16, 2018
@jmini

Copy link
Copy Markdown
Member

Java Technical Committee:
@bbdouglas (2017/07) @JFCote (2017/08) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01)
(we should have a Spring Technical Committee)

cc @macjohnny

@cbornet

Copy link
Copy Markdown
Member

It’s better to return a ResponseEntity to give the possibility for the implementer to set the Http status code and headers

@ilya1st

Copy link
Copy Markdown
Author

@cbornet that is wrong way cause with ResponseEntity you have to set http status code only once, before data is fetched and computed(before you know them). And cannot change them to status you need. But you can set them with WebExchange e.g.

exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);

After you fetch your data. And this is more flexible way than using ResponseEntity and exception handlers

@macjohnny

macjohnny commented Jul 18, 2018

Copy link
Copy Markdown
Member

@ilya1st it might be helpful for reviewing to optimize the PR. could you please

@cbornet

Copy link
Copy Markdown
Member

@ilya1st I'm not saying that the current implementation is OK but that we should keep the ResponseEntity. So return Mono<ResponseEntity<Foo>> and Mono<ResponseEntity<Flux<Foo>>>
The ServerWebExchange could also be passed (you would have to put it in the method arguments) but it's not as handy as ResponseEntity.

@cbornet

cbornet commented Jul 18, 2018

Copy link
Copy Markdown
Member

Actually the ServerWebExchange is already passed (we use it for the examples). Which is a good thing since it's the layer that gives the most flexibility (you can force the payload with untyped/raw data, etc...)

@ilya1st

Copy link
Copy Markdown
Author

@macjohnny I've reset branch to commit with mustache fixes.
There are some diffuculties with generating sources cause I have to work on Windows 7 machine and git marks some files 755 there :)

@wing328

Copy link
Copy Markdown
Member

I've updated the Petstore samples via e5f222d. Let's see how it goes.

@cbornet

Copy link
Copy Markdown
Member

@wing328 Note that there are still changes required on this PR

@wing328

Copy link
Copy Markdown
Member

@cbornet thanks for the heads-up. I'm just trying to resolve the Shippable CI error. Let me update the samples one more time to see how it goes.

@wing328wing328 changed the title do java spring webflux controllers the right way[Java][Spring] do webflux controllers the right wayJul 31, 2018
@ilya1st

Copy link
Copy Markdown
Author

@cbornet We had to write our generator based on this generator class for our internal projects for webflux. There are some issues with wrong work of delegate methods and classes for example. There are to much issues to make PRs for them.

For webflux case code looks slack-baked. May be better idea for springboot webflux case write separate generator from scratch? For now templates are too overloaded with cases to prevent erros there.
I can do this job.

@dr4ke616dr4ke616 mentioned this pull request Aug 15, 2018
12 tasks
@IsaacDeLaRosa

Copy link
Copy Markdown

@cbornet Is support for Mono<ResponseEntity<Foo>> (or Flux) controllers coming soon? if so will these be the required params and the right way to use it?

import org.openapitools.codegen.config.CodegenConfigurator
import org.openapitools.codegen.DefaultGenerator
def swaggerSourceFile = 'ignoreThis'
def swaggerTargetFolder = 'src/generated/java'
task generateApi {
inputs.file("$projectDir/$swaggerSourceFile")
outputs.dir("$projectDir/$swaggerTargetFolder")
doLast {
def config = new CodegenConfigurator()
config.setInputSpec("file:///$projectDir/$swaggerSourceFile")
config.setOutputDir("$projectDir")
config.setGeneratorName('spring')
config.setAdditionalProperties([
'interfaceOnly' : 'true',
'reactive' : 'true',
'apiPackage' : 'ignoreThis',
'modelPackage' : 'ignoreThis',
'sourceFolder' : swaggerTargetFolder
])
new DefaultGenerator().opts(config.toClientOptInput()).generate()
}
}

@cbornet

Copy link
Copy Markdown
Member

@IsaacDeLaRosa see #913 . As for the gradle part, have you tried the gradle plugin ?

@cbornet

Copy link
Copy Markdown
Member

Workaround with the current templates : if you need to set the status code or the headers reactively, you can do so by setting them on the ServerWebExchange in the reactive body. Eg:

@OverridepublicResponseEntity<Mono<Void>> deletePet(LongpetId, StringapiKey, ServerWebExchangeexchange) {
Mono<Void> result = Mono.empty()
.doOnSuccess(it -> exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN))
.doOnSuccess(it -> exchange.getResponse().getHeaders().add("foo", "bar"))
.then();
returnResponseEntity.status(HttpStatus.OK).body(result);
}

@jrobison153

Copy link
Copy Markdown

Chiming in here in agreement with the OP. We've been looking at the generated Spring Web Reactive interfaces and the response type wrappings seem superfluous, this is using version openapi-generator:3.3.1. For an API that returns a collection of type Foo, we get a Java interface with the following response signature

Mono<ResponseEntity<Flux<Foo>>>

From all of our testing this behaves identically to Flux<Foo> from a reactive client's perspective. The additional Mono<ResponseEntity> adds additional code to each controller to add the type wrappings.

Is there a reason for this or can it be simplified to Flux<Foo> and Mono<Foo>. The ServerWebExchange is already present and gives all the control over the HTTP session needed. It seems the generated code could be simplified

@cbornet

Copy link
Copy Markdown
Member

The same about ResponseEntity could be said for the non-reactive generation. I agree that it could be an option not to wrap into ResponseEntity.

@jrobison153

Copy link
Copy Markdown

Thanks for the quick response @cbornet, is this something you would be willing to take a PR for? If so would you want it conditional on option or just outright make the generator always create Flux and Mono response types?

@cbornet

Copy link
Copy Markdown
Member

It shall be conditional with an option at least for backward compat. We can discuss on what should be the default. I don't know when I can find enough time for this...

@cbornet

cbornet commented Oct 24, 2018

Copy link
Copy Markdown
Member

I'm closing this PR as the webflux gen has been fixed in another one.
@jrobison153 please open another issue for the optional ResponseEntity.

@cbornetcbornet closed this Oct 24, 2018
@jrobison153

Copy link
Copy Markdown

will do, cheers

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@ilya1st@jmini@cbornet@macjohnny@wing328@IsaacDeLaRosa@jrobison153
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[Java][Spring] do webflux controllers the right way - #571

Closed
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master
Closed

[Java][Spring] do webflux controllers the right way#571
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master

Conversation

@ilya1st

@ilya1stilya1st commented Jul 16, 2018

Copy link
Copy Markdown

Hello, there is a problem with mustache templates for spring-boot-webflux reactive case.
ResponseEntity<Mono|Flux> is wrong way for this case.
Right way is to use @RestController annotation and return directly Flux or Mono objects from controllers.

Here is patchset to make generator do it right.

@ilya1stilya1st changed the title do webflux controllers the right waydo java spring webflux controllers the right wayJul 16, 2018
@jmini

Copy link
Copy Markdown
Member

Java Technical Committee:
@bbdouglas (2017/07) @JFCote (2017/08) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01)
(we should have a Spring Technical Committee)

cc @macjohnny

@cbornet

Copy link
Copy Markdown
Member

It’s better to return a ResponseEntity to give the possibility for the implementer to set the Http status code and headers

@ilya1st

Copy link
Copy Markdown
Author

@cbornet that is wrong way cause with ResponseEntity you have to set http status code only once, before data is fetched and computed(before you know them). And cannot change them to status you need. But you can set them with WebExchange e.g.

exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);

After you fetch your data. And this is more flexible way than using ResponseEntity and exception handlers

@macjohnny

macjohnny commented Jul 18, 2018

Copy link
Copy Markdown
Member

@ilya1st it might be helpful for reviewing to optimize the PR. could you please

@cbornet

Copy link
Copy Markdown
Member

@ilya1st I'm not saying that the current implementation is OK but that we should keep the ResponseEntity. So return Mono<ResponseEntity<Foo>> and Mono<ResponseEntity<Flux<Foo>>>
The ServerWebExchange could also be passed (you would have to put it in the method arguments) but it's not as handy as ResponseEntity.

@cbornet

cbornet commented Jul 18, 2018

Copy link
Copy Markdown
Member

Actually the ServerWebExchange is already passed (we use it for the examples). Which is a good thing since it's the layer that gives the most flexibility (you can force the payload with untyped/raw data, etc...)

@ilya1st

Copy link
Copy Markdown
Author

@macjohnny I've reset branch to commit with mustache fixes.
There are some diffuculties with generating sources cause I have to work on Windows 7 machine and git marks some files 755 there :)

@wing328

Copy link
Copy Markdown
Member

I've updated the Petstore samples via e5f222d. Let's see how it goes.

@cbornet

Copy link
Copy Markdown
Member

@wing328 Note that there are still changes required on this PR

@wing328

Copy link
Copy Markdown
Member

@cbornet thanks for the heads-up. I'm just trying to resolve the Shippable CI error. Let me update the samples one more time to see how it goes.

@wing328wing328 changed the title do java spring webflux controllers the right way[Java][Spring] do webflux controllers the right wayJul 31, 2018
@ilya1st

Copy link
Copy Markdown
Author

@cbornet We had to write our generator based on this generator class for our internal projects for webflux. There are some issues with wrong work of delegate methods and classes for example. There are to much issues to make PRs for them.

For webflux case code looks slack-baked. May be better idea for springboot webflux case write separate generator from scratch? For now templates are too overloaded with cases to prevent erros there.
I can do this job.

@dr4ke616dr4ke616 mentioned this pull request Aug 15, 2018
12 tasks
@IsaacDeLaRosa

Copy link
Copy Markdown

@cbornet Is support for Mono<ResponseEntity<Foo>> (or Flux) controllers coming soon? if so will these be the required params and the right way to use it?

import org.openapitools.codegen.config.CodegenConfigurator
import org.openapitools.codegen.DefaultGenerator
def swaggerSourceFile = 'ignoreThis'
def swaggerTargetFolder = 'src/generated/java'
task generateApi {
inputs.file("$projectDir/$swaggerSourceFile")
outputs.dir("$projectDir/$swaggerTargetFolder")
doLast {
def config = new CodegenConfigurator()
config.setInputSpec("file:///$projectDir/$swaggerSourceFile")
config.setOutputDir("$projectDir")
config.setGeneratorName('spring')
config.setAdditionalProperties([
'interfaceOnly' : 'true',
'reactive' : 'true',
'apiPackage' : 'ignoreThis',
'modelPackage' : 'ignoreThis',
'sourceFolder' : swaggerTargetFolder
])
new DefaultGenerator().opts(config.toClientOptInput()).generate()
}
}

@cbornet

Copy link
Copy Markdown
Member

@IsaacDeLaRosa see #913 . As for the gradle part, have you tried the gradle plugin ?

@cbornet

Copy link
Copy Markdown
Member

Workaround with the current templates : if you need to set the status code or the headers reactively, you can do so by setting them on the ServerWebExchange in the reactive body. Eg:

@OverridepublicResponseEntity<Mono<Void>> deletePet(LongpetId, StringapiKey, ServerWebExchangeexchange) {
Mono<Void> result = Mono.empty()
.doOnSuccess(it -> exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN))
.doOnSuccess(it -> exchange.getResponse().getHeaders().add("foo", "bar"))
.then();
returnResponseEntity.status(HttpStatus.OK).body(result);
}

@jrobison153

Copy link
Copy Markdown

Chiming in here in agreement with the OP. We've been looking at the generated Spring Web Reactive interfaces and the response type wrappings seem superfluous, this is using version openapi-generator:3.3.1. For an API that returns a collection of type Foo, we get a Java interface with the following response signature

Mono<ResponseEntity<Flux<Foo>>>

From all of our testing this behaves identically to Flux<Foo> from a reactive client's perspective. The additional Mono<ResponseEntity> adds additional code to each controller to add the type wrappings.

Is there a reason for this or can it be simplified to Flux<Foo> and Mono<Foo>. The ServerWebExchange is already present and gives all the control over the HTTP session needed. It seems the generated code could be simplified

@cbornet

Copy link
Copy Markdown
Member

The same about ResponseEntity could be said for the non-reactive generation. I agree that it could be an option not to wrap into ResponseEntity.

@jrobison153

Copy link
Copy Markdown

Thanks for the quick response @cbornet, is this something you would be willing to take a PR for? If so would you want it conditional on option or just outright make the generator always create Flux and Mono response types?

@cbornet

Copy link
Copy Markdown
Member

It shall be conditional with an option at least for backward compat. We can discuss on what should be the default. I don't know when I can find enough time for this...

@cbornet

cbornet commented Oct 24, 2018

Copy link
Copy Markdown
Member

I'm closing this PR as the webflux gen has been fixed in another one.
@jrobison153 please open another issue for the optional ResponseEntity.

@cbornetcbornet closed this Oct 24, 2018
@jrobison153

Copy link
Copy Markdown

will do, cheers

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@ilya1st@jmini@cbornet@macjohnny@wing328@IsaacDeLaRosa@jrobison153
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[Java][Spring] do webflux controllers the right way - #571

Closed
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master
Closed

[Java][Spring] do webflux controllers the right way#571
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master

Conversation

@ilya1st

@ilya1stilya1st commented Jul 16, 2018

Copy link
Copy Markdown

Hello, there is a problem with mustache templates for spring-boot-webflux reactive case.
ResponseEntity<Mono|Flux> is wrong way for this case.
Right way is to use @RestController annotation and return directly Flux or Mono objects from controllers.

Here is patchset to make generator do it right.

@ilya1stilya1st changed the title do webflux controllers the right waydo java spring webflux controllers the right wayJul 16, 2018
@jmini

Copy link
Copy Markdown
Member

Java Technical Committee:
@bbdouglas (2017/07) @JFCote (2017/08) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01)
(we should have a Spring Technical Committee)

cc @macjohnny

@cbornet

Copy link
Copy Markdown
Member

It’s better to return a ResponseEntity to give the possibility for the implementer to set the Http status code and headers

@ilya1st

Copy link
Copy Markdown
Author

@cbornet that is wrong way cause with ResponseEntity you have to set http status code only once, before data is fetched and computed(before you know them). And cannot change them to status you need. But you can set them with WebExchange e.g.

exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);

After you fetch your data. And this is more flexible way than using ResponseEntity and exception handlers

@macjohnny

macjohnny commented Jul 18, 2018

Copy link
Copy Markdown
Member

@ilya1st it might be helpful for reviewing to optimize the PR. could you please

@cbornet

Copy link
Copy Markdown
Member

@ilya1st I'm not saying that the current implementation is OK but that we should keep the ResponseEntity. So return Mono<ResponseEntity<Foo>> and Mono<ResponseEntity<Flux<Foo>>>
The ServerWebExchange could also be passed (you would have to put it in the method arguments) but it's not as handy as ResponseEntity.

@cbornet

cbornet commented Jul 18, 2018

Copy link
Copy Markdown
Member

Actually the ServerWebExchange is already passed (we use it for the examples). Which is a good thing since it's the layer that gives the most flexibility (you can force the payload with untyped/raw data, etc...)

@ilya1st

Copy link
Copy Markdown
Author

@macjohnny I've reset branch to commit with mustache fixes.
There are some diffuculties with generating sources cause I have to work on Windows 7 machine and git marks some files 755 there :)

@wing328

Copy link
Copy Markdown
Member

I've updated the Petstore samples via e5f222d. Let's see how it goes.

@cbornet

Copy link
Copy Markdown
Member

@wing328 Note that there are still changes required on this PR

@wing328

Copy link
Copy Markdown
Member

@cbornet thanks for the heads-up. I'm just trying to resolve the Shippable CI error. Let me update the samples one more time to see how it goes.

@wing328wing328 changed the title do java spring webflux controllers the right way[Java][Spring] do webflux controllers the right wayJul 31, 2018
@ilya1st

Copy link
Copy Markdown
Author

@cbornet We had to write our generator based on this generator class for our internal projects for webflux. There are some issues with wrong work of delegate methods and classes for example. There are to much issues to make PRs for them.

For webflux case code looks slack-baked. May be better idea for springboot webflux case write separate generator from scratch? For now templates are too overloaded with cases to prevent erros there.
I can do this job.

@dr4ke616dr4ke616 mentioned this pull request Aug 15, 2018
12 tasks
@IsaacDeLaRosa

Copy link
Copy Markdown

@cbornet Is support for Mono<ResponseEntity<Foo>> (or Flux) controllers coming soon? if so will these be the required params and the right way to use it?

import org.openapitools.codegen.config.CodegenConfigurator
import org.openapitools.codegen.DefaultGenerator
def swaggerSourceFile = 'ignoreThis'
def swaggerTargetFolder = 'src/generated/java'
task generateApi {
inputs.file("$projectDir/$swaggerSourceFile")
outputs.dir("$projectDir/$swaggerTargetFolder")
doLast {
def config = new CodegenConfigurator()
config.setInputSpec("file:///$projectDir/$swaggerSourceFile")
config.setOutputDir("$projectDir")
config.setGeneratorName('spring')
config.setAdditionalProperties([
'interfaceOnly' : 'true',
'reactive' : 'true',
'apiPackage' : 'ignoreThis',
'modelPackage' : 'ignoreThis',
'sourceFolder' : swaggerTargetFolder
])
new DefaultGenerator().opts(config.toClientOptInput()).generate()
}
}

@cbornet

Copy link
Copy Markdown
Member

@IsaacDeLaRosa see #913 . As for the gradle part, have you tried the gradle plugin ?

@cbornet

Copy link
Copy Markdown
Member

Workaround with the current templates : if you need to set the status code or the headers reactively, you can do so by setting them on the ServerWebExchange in the reactive body. Eg:

@OverridepublicResponseEntity<Mono<Void>> deletePet(LongpetId, StringapiKey, ServerWebExchangeexchange) {
Mono<Void> result = Mono.empty()
.doOnSuccess(it -> exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN))
.doOnSuccess(it -> exchange.getResponse().getHeaders().add("foo", "bar"))
.then();
returnResponseEntity.status(HttpStatus.OK).body(result);
}

@jrobison153

Copy link
Copy Markdown

Chiming in here in agreement with the OP. We've been looking at the generated Spring Web Reactive interfaces and the response type wrappings seem superfluous, this is using version openapi-generator:3.3.1. For an API that returns a collection of type Foo, we get a Java interface with the following response signature

Mono<ResponseEntity<Flux<Foo>>>

From all of our testing this behaves identically to Flux<Foo> from a reactive client's perspective. The additional Mono<ResponseEntity> adds additional code to each controller to add the type wrappings.

Is there a reason for this or can it be simplified to Flux<Foo> and Mono<Foo>. The ServerWebExchange is already present and gives all the control over the HTTP session needed. It seems the generated code could be simplified

@cbornet

Copy link
Copy Markdown
Member

The same about ResponseEntity could be said for the non-reactive generation. I agree that it could be an option not to wrap into ResponseEntity.

@jrobison153

Copy link
Copy Markdown

Thanks for the quick response @cbornet, is this something you would be willing to take a PR for? If so would you want it conditional on option or just outright make the generator always create Flux and Mono response types?

@cbornet

Copy link
Copy Markdown
Member

It shall be conditional with an option at least for backward compat. We can discuss on what should be the default. I don't know when I can find enough time for this...

@cbornet

cbornet commented Oct 24, 2018

Copy link
Copy Markdown
Member

I'm closing this PR as the webflux gen has been fixed in another one.
@jrobison153 please open another issue for the optional ResponseEntity.

@cbornetcbornet closed this Oct 24, 2018
@jrobison153

Copy link
Copy Markdown

will do, cheers

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@ilya1st@jmini@cbornet@macjohnny@wing328@IsaacDeLaRosa@jrobison153
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[Java][Spring] do webflux controllers the right way - #571

Closed
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master
Closed

[Java][Spring] do webflux controllers the right way#571
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master

Conversation

@ilya1st

@ilya1stilya1st commented Jul 16, 2018

Copy link
Copy Markdown

Hello, there is a problem with mustache templates for spring-boot-webflux reactive case.
ResponseEntity<Mono|Flux> is wrong way for this case.
Right way is to use @RestController annotation and return directly Flux or Mono objects from controllers.

Here is patchset to make generator do it right.

@ilya1stilya1st changed the title do webflux controllers the right waydo java spring webflux controllers the right wayJul 16, 2018
@jmini

Copy link
Copy Markdown
Member

Java Technical Committee:
@bbdouglas (2017/07) @JFCote (2017/08) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01)
(we should have a Spring Technical Committee)

cc @macjohnny

@cbornet

Copy link
Copy Markdown
Member

It’s better to return a ResponseEntity to give the possibility for the implementer to set the Http status code and headers

@ilya1st

Copy link
Copy Markdown
Author

@cbornet that is wrong way cause with ResponseEntity you have to set http status code only once, before data is fetched and computed(before you know them). And cannot change them to status you need. But you can set them with WebExchange e.g.

exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);

After you fetch your data. And this is more flexible way than using ResponseEntity and exception handlers

@macjohnny

macjohnny commented Jul 18, 2018

Copy link
Copy Markdown
Member

@ilya1st it might be helpful for reviewing to optimize the PR. could you please

@cbornet

Copy link
Copy Markdown
Member

@ilya1st I'm not saying that the current implementation is OK but that we should keep the ResponseEntity. So return Mono<ResponseEntity<Foo>> and Mono<ResponseEntity<Flux<Foo>>>
The ServerWebExchange could also be passed (you would have to put it in the method arguments) but it's not as handy as ResponseEntity.

@cbornet

cbornet commented Jul 18, 2018

Copy link
Copy Markdown
Member

Actually the ServerWebExchange is already passed (we use it for the examples). Which is a good thing since it's the layer that gives the most flexibility (you can force the payload with untyped/raw data, etc...)

@ilya1st

Copy link
Copy Markdown
Author

@macjohnny I've reset branch to commit with mustache fixes.
There are some diffuculties with generating sources cause I have to work on Windows 7 machine and git marks some files 755 there :)

@wing328

Copy link
Copy Markdown
Member

I've updated the Petstore samples via e5f222d. Let's see how it goes.

@cbornet

Copy link
Copy Markdown
Member

@wing328 Note that there are still changes required on this PR

@wing328

Copy link
Copy Markdown
Member

@cbornet thanks for the heads-up. I'm just trying to resolve the Shippable CI error. Let me update the samples one more time to see how it goes.

@wing328wing328 changed the title do java spring webflux controllers the right way[Java][Spring] do webflux controllers the right wayJul 31, 2018
@ilya1st

Copy link
Copy Markdown
Author

@cbornet We had to write our generator based on this generator class for our internal projects for webflux. There are some issues with wrong work of delegate methods and classes for example. There are to much issues to make PRs for them.

For webflux case code looks slack-baked. May be better idea for springboot webflux case write separate generator from scratch? For now templates are too overloaded with cases to prevent erros there.
I can do this job.

@dr4ke616dr4ke616 mentioned this pull request Aug 15, 2018
12 tasks
@IsaacDeLaRosa

Copy link
Copy Markdown

@cbornet Is support for Mono<ResponseEntity<Foo>> (or Flux) controllers coming soon? if so will these be the required params and the right way to use it?

import org.openapitools.codegen.config.CodegenConfigurator
import org.openapitools.codegen.DefaultGenerator
def swaggerSourceFile = 'ignoreThis'
def swaggerTargetFolder = 'src/generated/java'
task generateApi {
inputs.file("$projectDir/$swaggerSourceFile")
outputs.dir("$projectDir/$swaggerTargetFolder")
doLast {
def config = new CodegenConfigurator()
config.setInputSpec("file:///$projectDir/$swaggerSourceFile")
config.setOutputDir("$projectDir")
config.setGeneratorName('spring')
config.setAdditionalProperties([
'interfaceOnly' : 'true',
'reactive' : 'true',
'apiPackage' : 'ignoreThis',
'modelPackage' : 'ignoreThis',
'sourceFolder' : swaggerTargetFolder
])
new DefaultGenerator().opts(config.toClientOptInput()).generate()
}
}

@cbornet

Copy link
Copy Markdown
Member

@IsaacDeLaRosa see #913 . As for the gradle part, have you tried the gradle plugin ?

@cbornet

Copy link
Copy Markdown
Member

Workaround with the current templates : if you need to set the status code or the headers reactively, you can do so by setting them on the ServerWebExchange in the reactive body. Eg:

@OverridepublicResponseEntity<Mono<Void>> deletePet(LongpetId, StringapiKey, ServerWebExchangeexchange) {
Mono<Void> result = Mono.empty()
.doOnSuccess(it -> exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN))
.doOnSuccess(it -> exchange.getResponse().getHeaders().add("foo", "bar"))
.then();
returnResponseEntity.status(HttpStatus.OK).body(result);
}

@jrobison153

Copy link
Copy Markdown

Chiming in here in agreement with the OP. We've been looking at the generated Spring Web Reactive interfaces and the response type wrappings seem superfluous, this is using version openapi-generator:3.3.1. For an API that returns a collection of type Foo, we get a Java interface with the following response signature

Mono<ResponseEntity<Flux<Foo>>>

From all of our testing this behaves identically to Flux<Foo> from a reactive client's perspective. The additional Mono<ResponseEntity> adds additional code to each controller to add the type wrappings.

Is there a reason for this or can it be simplified to Flux<Foo> and Mono<Foo>. The ServerWebExchange is already present and gives all the control over the HTTP session needed. It seems the generated code could be simplified

@cbornet

Copy link
Copy Markdown
Member

The same about ResponseEntity could be said for the non-reactive generation. I agree that it could be an option not to wrap into ResponseEntity.

@jrobison153

Copy link
Copy Markdown

Thanks for the quick response @cbornet, is this something you would be willing to take a PR for? If so would you want it conditional on option or just outright make the generator always create Flux and Mono response types?

@cbornet

Copy link
Copy Markdown
Member

It shall be conditional with an option at least for backward compat. We can discuss on what should be the default. I don't know when I can find enough time for this...

@cbornet

cbornet commented Oct 24, 2018

Copy link
Copy Markdown
Member

I'm closing this PR as the webflux gen has been fixed in another one.
@jrobison153 please open another issue for the optional ResponseEntity.

@cbornetcbornet closed this Oct 24, 2018
@jrobison153

Copy link
Copy Markdown

will do, cheers

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@ilya1st@jmini@cbornet@macjohnny@wing328@IsaacDeLaRosa@jrobison153
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[Java][Spring] do webflux controllers the right way - #571

Closed
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master
Closed

[Java][Spring] do webflux controllers the right way#571
ilya1st wants to merge 2 commits into
OpenAPITools:masterfrom
ilya1st:master

Conversation

@ilya1st

@ilya1stilya1st commented Jul 16, 2018

Copy link
Copy Markdown

Hello, there is a problem with mustache templates for spring-boot-webflux reactive case.
ResponseEntity<Mono|Flux> is wrong way for this case.
Right way is to use @RestController annotation and return directly Flux or Mono objects from controllers.

Here is patchset to make generator do it right.

@ilya1stilya1st changed the title do webflux controllers the right waydo java spring webflux controllers the right wayJul 16, 2018
@jmini

Copy link
Copy Markdown
Member

Java Technical Committee:
@bbdouglas (2017/07) @JFCote (2017/08) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01)
(we should have a Spring Technical Committee)

cc @macjohnny

@cbornet

Copy link
Copy Markdown
Member

It’s better to return a ResponseEntity to give the possibility for the implementer to set the Http status code and headers

@ilya1st

Copy link
Copy Markdown
Author

@cbornet that is wrong way cause with ResponseEntity you have to set http status code only once, before data is fetched and computed(before you know them). And cannot change them to status you need. But you can set them with WebExchange e.g.

exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);

After you fetch your data. And this is more flexible way than using ResponseEntity and exception handlers

@macjohnny

macjohnny commented Jul 18, 2018

Copy link
Copy Markdown
Member

@ilya1st it might be helpful for reviewing to optimize the PR. could you please

@cbornet

Copy link
Copy Markdown
Member

@ilya1st I'm not saying that the current implementation is OK but that we should keep the ResponseEntity. So return Mono<ResponseEntity<Foo>> and Mono<ResponseEntity<Flux<Foo>>>
The ServerWebExchange could also be passed (you would have to put it in the method arguments) but it's not as handy as ResponseEntity.

@cbornet

cbornet commented Jul 18, 2018

Copy link
Copy Markdown
Member

Actually the ServerWebExchange is already passed (we use it for the examples). Which is a good thing since it's the layer that gives the most flexibility (you can force the payload with untyped/raw data, etc...)

@ilya1st

Copy link
Copy Markdown
Author

@macjohnny I've reset branch to commit with mustache fixes.
There are some diffuculties with generating sources cause I have to work on Windows 7 machine and git marks some files 755 there :)

@wing328

Copy link
Copy Markdown
Member

I've updated the Petstore samples via e5f222d. Let's see how it goes.

@cbornet

Copy link
Copy Markdown
Member

@wing328 Note that there are still changes required on this PR

@wing328

Copy link
Copy Markdown
Member

@cbornet thanks for the heads-up. I'm just trying to resolve the Shippable CI error. Let me update the samples one more time to see how it goes.

@wing328wing328 changed the title do java spring webflux controllers the right way[Java][Spring] do webflux controllers the right wayJul 31, 2018
@ilya1st

Copy link
Copy Markdown
Author

@cbornet We had to write our generator based on this generator class for our internal projects for webflux. There are some issues with wrong work of delegate methods and classes for example. There are to much issues to make PRs for them.

For webflux case code looks slack-baked. May be better idea for springboot webflux case write separate generator from scratch? For now templates are too overloaded with cases to prevent erros there.
I can do this job.

@dr4ke616dr4ke616 mentioned this pull request Aug 15, 2018
12 tasks
@IsaacDeLaRosa

Copy link
Copy Markdown

@cbornet Is support for Mono<ResponseEntity<Foo>> (or Flux) controllers coming soon? if so will these be the required params and the right way to use it?

import org.openapitools.codegen.config.CodegenConfigurator
import org.openapitools.codegen.DefaultGenerator
def swaggerSourceFile = 'ignoreThis'
def swaggerTargetFolder = 'src/generated/java'
task generateApi {
inputs.file("$projectDir/$swaggerSourceFile")
outputs.dir("$projectDir/$swaggerTargetFolder")
doLast {
def config = new CodegenConfigurator()
config.setInputSpec("file:///$projectDir/$swaggerSourceFile")
config.setOutputDir("$projectDir")
config.setGeneratorName('spring')
config.setAdditionalProperties([
'interfaceOnly' : 'true',
'reactive' : 'true',
'apiPackage' : 'ignoreThis',
'modelPackage' : 'ignoreThis',
'sourceFolder' : swaggerTargetFolder
])
new DefaultGenerator().opts(config.toClientOptInput()).generate()
}
}

@cbornet

Copy link
Copy Markdown
Member

@IsaacDeLaRosa see #913 . As for the gradle part, have you tried the gradle plugin ?

@cbornet

Copy link
Copy Markdown
Member

Workaround with the current templates : if you need to set the status code or the headers reactively, you can do so by setting them on the ServerWebExchange in the reactive body. Eg:

@OverridepublicResponseEntity<Mono<Void>> deletePet(LongpetId, StringapiKey, ServerWebExchangeexchange) {
Mono<Void> result = Mono.empty()
.doOnSuccess(it -> exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN))
.doOnSuccess(it -> exchange.getResponse().getHeaders().add("foo", "bar"))
.then();
returnResponseEntity.status(HttpStatus.OK).body(result);
}

@jrobison153

Copy link
Copy Markdown

Chiming in here in agreement with the OP. We've been looking at the generated Spring Web Reactive interfaces and the response type wrappings seem superfluous, this is using version openapi-generator:3.3.1. For an API that returns a collection of type Foo, we get a Java interface with the following response signature

Mono<ResponseEntity<Flux<Foo>>>

From all of our testing this behaves identically to Flux<Foo> from a reactive client's perspective. The additional Mono<ResponseEntity> adds additional code to each controller to add the type wrappings.

Is there a reason for this or can it be simplified to Flux<Foo> and Mono<Foo>. The ServerWebExchange is already present and gives all the control over the HTTP session needed. It seems the generated code could be simplified

@cbornet

Copy link
Copy Markdown
Member

The same about ResponseEntity could be said for the non-reactive generation. I agree that it could be an option not to wrap into ResponseEntity.

@jrobison153

Copy link
Copy Markdown

Thanks for the quick response @cbornet, is this something you would be willing to take a PR for? If so would you want it conditional on option or just outright make the generator always create Flux and Mono response types?

@cbornet

Copy link
Copy Markdown
Member

It shall be conditional with an option at least for backward compat. We can discuss on what should be the default. I don't know when I can find enough time for this...

@cbornet

cbornet commented Oct 24, 2018

Copy link
Copy Markdown
Member

I'm closing this PR as the webflux gen has been fixed in another one.
@jrobison153 please open another issue for the optional ResponseEntity.

@cbornetcbornet closed this Oct 24, 2018
@jrobison153

Copy link
Copy Markdown

will do, cheers

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@ilya1st@jmini@cbornet@macjohnny@wing328@IsaacDeLaRosa@jrobison153