Description
I am working with Grails 3.1.4 and I am having problems documenting my Controller classes with the Swagger Api.
grails -version gives me this output:
| Grails Version: 3.1.4
| Groovy Version: 2.4.6
| JVM Version: 1.8.0_73
I tried to integrate Swagger into the project using these sources:
- https://grails.org/plugin/swaggydoc
- https://rahulsom.github.io/swaggydoc/
According to these sources I have to do the following things:
1. Add dependencies to build.gradle:
compile 'io.swagger:swagger-core:1.5.7'
compile 'io.swagger:swagger-jaxrs:1.5.7'
compile "com.github.rahulsom:swaggydoc-commons:0.24.0"
compile "org.grails.plugins:swaggydoc:0.27.0"
2. Add another repository to build.gradle:
`jcenter()`
3. Annotate my Controller in the following fashion:
#Api(value = "myValue", description = "this controller does something")
#Path("/myapproot/myDomainClassX")
MyDomainClassXController{
#GET
#Path("/myFunction")
def myFunction(){
render "MyDomainClassXController, myFunction(), did something"
}
}
4. In the file application.yml I added:
grails:
mime:
disable:
accept:
header:
userAgents: []
5. The aforementioned sources write about a Config.groovy which I do not have, so instead of writing:
swaggydoc {
contact = "developer#coer.com"
description = "API description"
title = "My Swagger Doc for my awesome project"
apiVersion = "0.2cents"
}
6. into the non-existent Config.groovy, I added the same text into the file application.yml using the yml syntax:
swaggydoc:
contact: "developer#coder.com"
description: "API Description"
title: "My Swagger Doc for my awesome project"
apiVersion: "0.2cents"
Result
What works is:
I am running my Grails application with the bootRun task and browse to http://localhost:8080/myapproot/myDomainClassX/myFunction and see the String "MyDomainClassXController, myFunction(), did something" in my browser.
What not works is:
When I browse to http://localhost:8080/myapproot/api I get the "Page Not Found (404)" Error. Here i expected to see the magic of the Swagger annotations producing a documentation.
Question
What did I do wrong in the configuration of the Swagger plugin mentioned in the sources?
If you are getting a 404 on /myapproot/api check your UrlMappings.groovy file.
Either leave this default mapping in there:
"/$controller/$action?/$id?(.$format)?"{
constraints {
// apply constraints here
}
}
or at least allow
get "/api/$action?"(controller: 'api')
That should let you at least hit the swaggy controller with that URL.
Related
I am using Azure API Management to host three versions of an API - dev, qa, stage. These are basically three different build configurations of the api, so when imported to APIM - "MyAPI-dev", "MyAPI-qa", "MyAPI-stage".
I am using swagger for documentation. When I trigger a revision in Terraform to build/re-create the API definitions, i am getting error:
"my-ApiM-dev" / Resource Group "rg-myApim"): apimanagement.APIClient#CreateOrUpdate: Failure sending
request: StatusCode=409 -- Original Error: Code="IdentifierAlreadyInUse" Message="Resource already exists."
I am 99% sure this is due to the "title" in SwaggerConfig.cs file, it is the same value for all configurations. Thus deploying two of the APIs with the same title is throwing the error.
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "MyApiTitle");
}
How can I get the title to be unique based on the configuration?
I tried creating config values in web.config value for each configuration and referencing the key in the config file, but it didn't work, SwaggerUi picked up the default value in web.config file only.
web.dev.config:
<add key="BuildConfig" value="dev" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
SwaggerConfig.cs:
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "MyApiTitle-" + ConfigurationManager.AppSettings["BuildConfig"]);
}
Another option is to script deleting the API, import the API and rename the title, but I would do that as a last resort.
Would like to do this dynamically in the project code though.
I am able to achieve this with PowerShell, please check if that helps to you
https://medium.com/#rakesh.suryawanshi/deploy-azure-web-api-into-azure-api-management-with-powershell-3d14d1610b07
also, check if you are able to deploy it manually with your approach.
I'm quite new to Jenkins, Groovy and all that, so forgive me if this sounds dumb.
I'm using the Active Choices plugin, and from one of the AC Parameters inside the Groovy script I want to use a different plugin - Artifactory, to fetch a file and display each line inside it as an option.
try {
def server = Artifactory.newServer url: 'http://localhost:8081/artifactory/', username: 'user', password: 'pass'
def downloadSpec = """{
"files": [
{
"pattern": "example-repo-local/file.txt",
"target": "example/"
}
]
}"""
server.download(downloadSpec)
String text = readFile("example/file.txt")
return text.tokenize("\n")
} catch (Exception e) {
return [e]
}
However, the Active Choices Parameter doesn't seem to recognize other plugins, and it can't find the Artifactory property:
groovy.lang.MissingPropertyException: No such property: Artifactory for class: Script1
My question is - do I need to import the plugin somehow? If so, how do I determine what to import?
There is an option to also specify an "Additional classpath" near an Active Choice Parameter, but the plugin contains 75 jar files in its WEB-INF/lib directory. (just specifying the artifactory.jar one doesn't seem to change anything)
Just a note - the Pipeline recognizes the Artifactory plugin and it works fine - I can successfully connect and retreive a file and read it.
I can't fine any possibility to run Artifactory plugin in reasonable way. So i thing better option is use curl, and Artifactory API. For example my Active Choices Parameter based on Json file from Artifactory;
import groovy.json.JsonSlurper
def choices = []
def response = ["curl", "-k", "https://artifactory/app/file.json"].execute().text
def list = new JsonSlurper().parseText( response )
list.each { choices.push(it.name) }
return choices
I'm attempting to document my API using Swagger by writing the documentation in the Swagger editor and then loading it into the Swagger UI. I used the editor and downloaded my JSON file and then changed the /dist/index.html file within the UI to point to my local file using:
var spec = "file:///Users/user1/Desktop/swagger.json";
if (url && url.length > 1) {
url = decodeURIComponent(url[1]);
} else {
url = "http://petstore.swagger.io/v2/swagger.json";
}
// Pre load translate...
if(window.SwaggerTranslator) {
window.SwaggerTranslator.translate();
}
window.swaggerUi = new SwaggerUi({
url: url,
spec: spec,
The only thing I changed within the file is the use of the spec var to point to my JSON file, however when I open the UI, it displays a blank UI page with the message "Finished Loading Resource Information. Rendering Swagger UI..." I would just like to display the documentation I created in the editor in the UI without having to host the specs, is there something I'm missing?
Accordign to the Documentation, spec value must be an JSON Object, so you have to do something like:
window.swaggerUi = new SwaggerUi({
spec: JSON.parse('{ "swagger": "2.0", ...')
where
{ "swagger": "2.0", ...
is the content for your file:///Users/user1/Desktop/swagger.json file
I am trying to upgrade my application from grails 2 to grails 3. However, the functional test which is working in grails 2 fails to run now. In grails 2, I use RestBuilder to send request and get response. In grails 3, there is no corresponding RestBuilder release. How can I send my post and get request in grails 3 functional test?
Thanks very much.
My test code in grails 2:
void testRequestNewEnvironment() {
setup:
def rest = new RestBuilder(connectTimeout:1000, readTimeout:20000)
int timeout = 10
String environmentId = 0
String environmentStatus = "Not Ready"
when:
/**
* PostMethod. Send out a post and response status should be 200 and the body of response include env_id
*/
def resp = rest.post('http://localhost:8080/test-environment-manager/environment') {
contentType "multipart/form-data"
buildfile= new File('script.sh')
username = "apps"
keepEnvflag = "false"
env_flavor = "default"
}
then:
resp.getStatus() == 200
environmentId = resp.json.env_id
println "Environment ID: $environmentId"
println ("Environment Status"+resp.json.Status)
I use RESTClient for executing HTTP requests in Grails functional tests. It's a class from the HTTPBuilder library, so it should work in every Grails version (because it has dependency on Grails).
Some example usages are shown here. Before you can use it, you'll need to add a dependency on this library by adding the following to build.gradle
compile 'org.codehaus.groovy.modules.http-builder:http-builder:0.7.1'
I added :
compile ":rest-client-builder:2.1.1"
and it works fine.
The following code works fine when deployed locally in a dev environment from a controller (using run-app). It's used to create a JavaScript object with all messages in the current language.
class LocaleController {
private Map<String, String> getMessages() {
// This is the line in question, the rest is just context
def bundle = ResourceBundle.getBundle("grails-app/i18n/messages");
def map = [:]
bundle.keys.each { msg ->
map[msg] = message(code: msg)
}
return map
}
def index() {
header("Cache-Control", "public, max-age=31536000")
render(view: "index", model: [messages: getMessages()], contentType: "text/javascript")
}
}
However, when this is run from a deployed server, I get the following error message
errors.GrailsExceptionResolver - MissingResourceException occurred when processing request: [GET] /compose/locale/index
Can't find bundle for base name grails-app/i18n/messages, locale en_US. Stacktrace follows:
java.util.MissingResourceException: Can't find bundle for base name grails-app/i18n/messages, locale en_US
at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:1499)
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1322)
at java.util.ResourceBundle.getBundle(ResourceBundle.java:1028)
at com.accelrys.compose.app.LocaleController.getMessages(LocaleController.groovy:13)
at com.accelrys.compose.app.LocaleController.index(LocaleController.groovy...
I would have preferred not to read the file directly, so I tried http://mrhaki.blogspot.com/2011/11/grails-goodness-internationalize.html which uses http://grails.org/plugin/jawr but that page has been offline for the past 10 days.
I also tried following the steps in How can I create a map with all i18n-messages in Grails but it wouldn't use my customized message source, I copied the answer verbatim (clean/comile/run-app) but it was still using PluginAwareResourceBundleMessageSource instead of ExtendedPluginAwareResourceBundleMessageSource
2014-09-29 17:15:33,447 [http-bio-8080-exec-2] ERROR errors.GrailsExceptionResolver - MissingMethodException occurred when processing request: [GET] /compose/locale/index - parameters: jklgfdgdfg:
No signature of method: org.codehaus.groovy.grails.context.support.PluginAwareResourceBundleMessageSource.getMessageCodes() is applicable for argument types: () values: []. Stacktrace follows:
Message: No signature of method: org.codehaus.groovy.grails.context.support.PluginAwareResourceBundleMessageSource.getMessageCodes() is applicable for argument types: () values: []
Line | Method
->> 15 | getMessages in com.accelrys.compose.app.LocaleController$$EOrHmJbB
Any suggestions on what else I can try?
It turns out that How can I create a map with all i18n-messages in Grails does work correctly.
I am not sure why it wasn't working, as one can see from the error message in the question. Maybe it had something to do with the following error at startup.
java.lang.RuntimeException: Reloading agent exited via exception, please raise a jira
Error |
at org.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform( ClassPreProcessorAgentAdapter.java:104)
Error |
In any case, if you try this and it doesn't work at first, don't give up. Try again later.
Update
It turns out that the reason the plugin didn't work was because grails install-plugin is deprecated, adding compile ":jawr:3.5.1" to the plugins section of BuildConfig.groovy made it work.