Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File not found exception restapidoc.json when app is deployed as war #12

Open
sunilinteti opened this issue Aug 1, 2014 · 11 comments
Open

Comments

@sunilinteti
Copy link

Hi,
I have deployed the grails application war. I have put the restapidoc.json file in the exploded war root directory. When I try to hit the url for the documentation it gives filenotfound error. It works fine locally when I start grails from grails run-app.
Could you please point out if I am missing some thing. Thank you.

URL : http://dev.mathmagicians.dk:8080/mo/restApiDoc/?doc_url=http://dev.mathmagicians.dk:8080/mo/restApiDoc/api

{"status":500,"message":"restapidoc.json (The system cannot find the file specified)","trace":"java.io.FileNotFoundException: restapidoc.json (The system cannot find the file specified)\r\n\tat java.io.FileInputStream.(FileInputStream.java:146)\r\n\tat org.restapidoc.RestApiDocController.api(RestApiDocController.groovy:20)\r\n\tat grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)\r\n\tat grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)\r\n\tat com.odobo.grails.plugin.springsecurity.rest.RestTokenValidationFilter.processFilterChain(RestTokenValidationFilter.groovy:88)\r\n\tat com.odobo.grails.plugin.springsecurity.rest.RestTokenValidationFilter.doFilter(RestTokenValidationFilter.groovy:66)\r\n\tat grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53)\r\n\tat dk.mathmagicians.mo.springsecurity.rest.CustomRestAuthenticationFilter.doFilter(CustomRestAuthenticationFilter.groovy:110)\r\n\tat grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:49)\r\n\tat grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:82)\r\n\tat dk.mathmagicians.mo.springsecurity.rest.CustomRestLogoutFilter.doFilter(CustomRestLogoutFilter.groovy:73)\r\n\tat com.brandseye.cors.CorsFilter.doFilter(CorsFilter.java:82)\r\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)\r\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)\r\n\tat java.lang.Thread.run(Thread.java:745)\r\n"}

@loic911
Copy link
Owner

loic911 commented Aug 1, 2014

Hi,
The json file must be in your app root directory.
It depends on your config/container (for my tomcat, its: /var/lib/tomcat7/restapidoc.json)

You should try:

  1. add this line in the init method from bootstrap.groovy
    println "resapidoc.json must be located in "+new File( 'restapidoc.json' ).absolutePath
  2. check your log file/console for this println and check if the restapidoc file is there

I will try to simplify this step in the next release ;-)

@loic911 loic911 closed this as completed Aug 1, 2014
@loic911 loic911 reopened this Aug 1, 2014
@mgeis
Copy link

mgeis commented Aug 7, 2014

The problem here is that the plugin expects to find it in the root of the app server, but the file is actually at ${root}/mo/restapidoc.json . The generated HTML will also look for javascript off the root of the app server, and will not look relative to the deployment context of the application (in this case, "mo").

This looks like a bug. If you repackage your war file to deploy as the root application (grails.app.context="/"), everything will work.

@dbk138
Copy link

dbk138 commented Sep 18, 2014

I have found that the configuration property 'grails.plugins.restapidoc.outputFile' controls both the location of the document when it gets generated through 'grails rest-api-doc' and the location used by the server to look for the file when deployed as a war file. This becomes an issue (at least for me) when you develop and deploy on separate systems. For example, if I have my property set to 'grails.plugins.restapidoc.outputFile="/home/user/app/restapidoc.json"' then it will generate that file in that location when I execute 'grails rest-api-doc'. However, when I go to deploy the app as a war file, the server will look for that location based on the property in the Config.groovy file and it will return the 500 error if it does not exist or cannot access it.

Based on this, would there be a way to seperate this behavior into two different properties? One to specify the output file when 'grails rest-api-doc' is executed and one for the location of the file on the server?

P.S. I have also tried the above suggestions, neither of which had worked. I am using Fedora 20 and deploying on RedHat 6 using WebSphere.

@loic911
Copy link
Owner

loic911 commented Sep 24, 2014

dbk138: this will be done in 0.4 (realease soon).

String outputFileGeneration: The path to the file where to store the JSON after generation
String outputFileReading: The path to the JSON file to read when looking for the report

You can have different value with different env (dev, prod, test, ...)

@raffian
Copy link

raffian commented Nov 2, 2014

@dbk138 Had the same problem, and I agree, we need another property.

For local development, and server deployment using exploded WAR, outputFileGeneration and outputFileReading work fine because the json file is readable using absolute paths and new File({outputFileReading}). When deploying as packaged WAR, this doesn't work, so I introduced a new property:

outputFileClasspathReading

If property is set, json file is read from the WAR's classpath (if not set, defaults to outputFileReading and new File() as before)

The war classpath is WEB-INF/classes, so I added a build event that triggers on grails war, adding the json file to the WAR:

//_Events.groovy
eventCreateWarStart = { warName, stagingDir ->
   def warClasspath = new File('${stagingDir}/WEB-INF/classes')
   ant.copy(todir: warClasspath ) {
      fileset(file:'restapidoc.json')
   }
}

I updated RestApiDocController to check if outputFileClasspathReading is enabled, if so, it uses getResourceAsStream() to access the file, if not, defaults to new File(), as before.

I'm trying to do my first pull request with these changes, but does that make sense?
I like this approach as it's flexible for local development and server deployment.

@ferasodh
Copy link

I had the same problem guys, but I can't make it work neither in dev nor in prod modes. I printed 'restapidoc.json' file path and it was as expected.
Here is my config:

grails.plugins.restapidoc.outputFileGeneration = "restapidoc.json"
grails.plugins.restapidoc.outputFileReading = "restapidoc.json"
grails.plugins.restapidoc.basePath = "http://localhost:8080/osp"

grails.plugins.restapidoc.defaultObjectFields = [
[name:"id", type:"Long"]
]
grails.plugins.restapidoc.defaultErrorAll = [
"400": "Bad Request: missing parameters or bad message format",
"401": "Unauthorized: must be auth",
"403": "Forbidden: role error",
"404": "Object not found"
]
grails.plugins.restapidoc.defaultErrorGet = [
"400": "Bad Request: missing parameters or bad message format",
"401": "Unauthorized: must be auth",
"403": "Forbidden: role error",
"404": "Object not found"
]
grails.plugins.restapidoc.defaultErrorPost = [
"409": "Object already exist"
]
grails.plugins.restapidoc.defaultErrorPut = [
"409": "Object already exist"
]

and this is my restapidoc.json file:

{
   "basePath": "http://localhost:8080/osp",
   "apis": [{
      "jsondocId": "af2bdcb8-03ea-4cf2-90cf-ff7020b31e50",
      "methods": [{
         "headers": [],
         "pathparameters": [{
            "jsondocId": "c4098614-a661-4d88-9f74-e17509bb9717",
            "name": "id",
            "format": "",
            "description": "Location id",
            "type": "long",
            "required": "true",
            "allowedvalues": []
         }],
         "queryparameters": [],
         "verb": "GET",
         "description": "Gets a Location",
         "methodName": "show",
         "jsondocId": "01a5724b-6ffe-45cb-9d78-411a359c6a75",
         "bodyobject": null,
         "apierrors": [
            {
               "jsondocId": "000cd55e-07a7-4dee-989b-eab1e00430f1",
               "code": "400",
               "description": "Bad Request: missing parameters or bad message format"
            },
            {
               "jsondocId": "da98e143-90d2-45a8-a344-79ad21792695",
               "code": "401",
               "description": "Unauthorized: must be auth"
            },
            {
               "jsondocId": "118d5820-a96a-4530-a8a7-4c490be3d3c4",
               "code": "403",
               "description": "Forbidden: role error"
            },
            {
               "jsondocId": "65e41c2a-e223-48f8-ae00-e4309fa8c21b",
               "code": "404",
               "description": "Object not found"
            }
         ],
         "path": "/api/coupons/{CouponId}locations/{id}",
         "response": {
            "jsondocId": "f378f3a9-5d7e-45d8-9011-18ae1934551d",
            "mapValueObject": "",
            "mapKeyObject": "",
            "object": "location"
         },
         "produces": ["application/json"],
         "consumes": []
      }],
      "name": "Location services",
      "description": "Methods for managing Locations"
   }],
   "objects": [],
   "version": "0.1.1"
}

Can you please help me solve this?

@loic911
Copy link
Owner

loic911 commented Feb 2, 2015

Could you locate the restapidoc.json file on your server (absolute path)?

With grails.plugins.restapidoc.outputFileReading = "restapidoc.json", the server will look on the "current" directory for this file.
It should be great if you can print the absolute path of the expected file:
In RestApiDocController.groovy, add the line:

println docFile.absolutePath

between these 2 lines:

File docFile = new File(grailsApplication.mergedConfig.grails.plugins.restapidoc.outputFileReading)
render(docFile.text)

@TonyVeigel
Copy link

@raffian That is a needed feature. You should issue that pull request.

@stacysimpson
Copy link
Contributor

As opposed to introducing another setting, an alternative approach is to use the servletContext. This approach will work for both development and production.

Example settings:
grails.plugins.restapidoc.outputFileGeneration = "web-app/WEB-INF/restapidoc.json"
grails.plugins.restapidoc.outputFileReading = "/WEB-INF/restapidoc.json"

Here is the pull request: #52

@raffian
Copy link

raffian commented May 20, 2015

Nice, how’s that working out for you in both local and prod evironments?

From: Stacy Simpson [mailto:[email protected]]
Sent: Tuesday, May 19, 2015 8:11 PM
To: loic911/Rest-api-doc
Cc: Raffi Basmajian
Subject: Re: [Rest-api-doc] File not found exception restapidoc.json when app is deployed as war (#12)

As opposed to introducing another setting, an alternative approach is to use the servletContext. This approach will work for both development and production.

Example settings:
grails.plugins.restapidoc.outputFileGeneration = "web-app/WEB-INF/restapidoc.json"
grails.plugins.restapidoc.outputFileReading = "/WEB-INF/restapidoc.json"

Here is the pull request: #52 #52


Reply to this email directly or view it on GitHub #12 (comment) . https://github.com/notifications/beacon/AENS2AlJZmt-HbQZBZPRX8MektqmEMC2ks5oK8iLgaJpZM4CTGp2.gif

@stacysimpson
Copy link
Contributor

Works fine. I tested on both Linux (development) and Windows (production).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants