Closed bogdanalexe closed 10 years ago
Only some methods? Do they have something special (multiple url mappings for this method,...)? Could you please provide more details (sample code for duplicated method documentation and/or the json sample with duplicated method)?
Thanks
All of them except those who have the "listing = true " parameter. Here is an example of annotation for the show method:
@RestApiMethod(description = "Get a member", path = "/api/members/{id}", verb = RestApiVerb.GET) @RestApiParams(params = [ @RestApiParam(name = "id", type = "Long", paramType = RestApiParamType.PATH) ]) @RestApiResponseObject(objectIdentifier = "Member")
And here is the generated JSON:
{ "basePath": "http://localhost:8080", "apis": [ { "methods": [ { "headers": [], "bodyobject": { "mapKeyObject": "", "jsondocId": "5b67ced3-f055-42e8-9e32-0df19a779611", "mapValueObject": "", "map": "", "object": "member", "multiple": "Unknow" }, "jsondocId": "02cf451f-aa78-413a-a9bb-63805ed8c695", "consumes": ["application/json"], "response": { "mapKeyObject": "", "jsondocId": "6f1de1c3-8c1f-412b-b372-ca65df1c7370", "mapValueObject": "", "object": "Member", "multiple": "false" }, "pathparameters": [], "apierrors": [ { "jsondocId": "be17331b-2a48-4a48-a6c0-e8f9b2128769", "description": "Internal Server Error", "code": "500" }, { "jsondocId": "abe00557-ecf9-4e4e-82be-01b25dc0a4fb", "description": "Validation failed", "code": "406" } ], "verb": "POST", "description": "Create a member", "queryparameters": [], "path": "/api/members", "produces": ["application/json"], "methodName": "save" }, { "headers": [], "bodyobject": { "mapKeyObject": "", "jsondocId": "97ce9da4-ae2d-4c98-897c-730436479bd6", "mapValueObject": "", "map": "", "object": "member", "multiple": "Unknow" }, "jsondocId": "0f0386e2-0b3f-4f35-aec2-1985f5ecb4e8", "consumes": ["application/json"], "response": { "mapKeyObject": "", "jsondocId": "509d309b-b1d0-4d11-992e-3026e5f2b072", "mapValueObject": "", "object": "Member", "multiple": "false" }, "pathparameters": [], "apierrors": [ { "jsondocId": "4d74ff8c-07a4-4b56-b428-a3bd01acb958", "description": "Internal Server Error", "code": "500" }, { "jsondocId": "84884f3c-7be4-4f97-82c3-206ee6807b86", "description": "Validation failed", "code": "406" } ], "verb": "POST", "description": "Create a member", "queryparameters": [], "path": "/api/members", "produces": ["application/json"], "methodName": "save" }, { "headers": [], "bodyobject": null, "jsondocId": "ec8b7605-3811-45e2-b388-389e69b2fb91", "consumes": [], "response": { "mapKeyObject": "", "jsondocId": "b75a41b9-d9d2-43c9-8992-bbddb16f4d62", "mapValueObject": "", "object": "List", "multiple": "Member" }, "pathparameters": [], "apierrors": [ { "jsondocId": "d90b9360-0bc0-4eed-9be6-f42f6670ad21", "description": "Internal Server Error", "code": "500" }, { "jsondocId": "c7c99d29-d1bb-4c1f-ae68-a8d4dfb98a68", "description": "Object not found", "code": "404" } ], "verb": "GET", "description": "List members", "queryparameters": [ { "jsondocId": "e505e087-c3fb-4f53-9ec5-bb7b2d9c4bf3", "description": "Limit for listing", "name": "max", "allowedvalues": [], "format": "", "required": "false", "type": "Integer" }, { "jsondocId": "f78e43a0-5374-49fc-9227-3ac3fc7c0797", "description": "Offset for listing", "name": "offset", "allowedvalues": [], "format": "", "required": "false", "type": "Integer" }, { "jsondocId": "89e39ba8-c065-467c-a611-319ca65c5bda", "description": "Sort by field", "name": "sort", "allowedvalues": [], "format": "", "required": "false", "type": "String" }, { "jsondocId": "d1ba4746-dc43-4506-b89a-e5e38af03c34", "description": "Order for sorting", "name": "order", "allowedvalues": [ "asc", "desc" ], "format": "", "required": "false", "type": "String" }, { "jsondocId": "ec3aec7b-152a-4def-a137-7e28bd6a4510", "description": "Limit by tag", "name": "tag", "allowedvalues": [], "format": "", "required": "false", "type": "String" }, { "jsondocId": "1e6fdf77-017b-4f1c-84eb-0a2dce0a12fd", "description": "Limit by sex", "name": "sex", "allowedvalues": [ "male", "female" ], "format": "", "required": "false", "type": "String" }, { "jsondocId": "2143fdf4-49f8-4cea-94a7-5fb7265c6140", "description": "Limit by isSubscribed", "name": "isSubscribed", "allowedvalues": [], "format": "", "required": "false", "type": "Boolean" }, { "jsondocId": "b9eb39fc-519a-41f5-b519-6c35fdf435ee", "description": "Limit by search string", "name": "q", "allowedvalues": [], "format": "", "required": "false", "type": "String" } ], "path": "/api/members", "produces": ["application/json"], "methodName": "index" }, { "headers": [], "bodyobject": null, "jsondocId": "8bd8eb6b-18eb-4c2b-bafd-cb65af0b1bbd", "consumes": [], "response": { "mapKeyObject": "", "jsondocId": "dc44aee2-ca41-4bcb-9cdb-90f6f36560ab", "mapValueObject": "", "object": "void", "multiple": "false" }, "pathparameters": [{ "jsondocId": "a71cf9a0-3c33-4871-a2ae-2e93f785b3fb", "description": "", "name": "id", "allowedvalues": [], "format": "", "required": "true", "type": "Long" }], "apierrors": [ { "jsondocId": "4b968067-b101-4e51-bef1-825e28c261fb", "description": "Internal Server Error", "code": "500" }, { "jsondocId": "bc0943f0-77b5-4a87-8d61-10fda0afd754", "description": "Object not found", "code": "404" } ], "verb": "DELETE", "description": "Delete a member", "queryparameters": [], "path": "/api/members/{id}", "produces": ["application/json"], "methodName": "delete" }, { "headers": [], "bodyobject": null, "jsondocId": "66b9bab7-5531-4079-97f9-e6d190811e19", "consumes": [], "response": { "mapKeyObject": "", "jsondocId": "63dc3ba4-740e-4336-b725-570ada2ceddb", "mapValueObject": "", "object": "void", "multiple": "false" }, "pathparameters": [{ "jsondocId": "49da73ef-4aef-4fdd-9085-392a1462f21b", "description": "", "name": "id", "allowedvalues": [], "format": "", "required": "true", "type": "Long" }], "apierrors": [ { "jsondocId": "a25e61ff-6e67-493f-9037-bb98ba826aa6", "description": "Internal Server Error", "code": "500" }, { "jsondocId": "ebfa87fb-af0d-403c-b684-6561e84ab1d1", "description": "Object not found", "code": "404" } ], "verb": "DELETE", "description": "Delete a member", "queryparameters": [], "path": "/api/members/{id}", "produces": ["application/json"], "methodName": "delete" }, { "headers": [], "bodyobject": { "mapKeyObject": "", "jsondocId": "82102ec4-b939-4e27-9673-d191dcb50b98", "mapValueObject": "", "map": "", "object": "member", "multiple": "Unknow" }, "jsondocId": "ef29d6ef-e54f-44bb-a138-c2b7b794829d", "consumes": ["application/json"], "response": { "mapKeyObject": "", "jsondocId": "9579207a-08a8-4994-844a-779f7bfcfeaf", "mapValueObject": "", "object": "Member", "multiple": "false" }, "pathparameters": [{ "jsondocId": "f21bd0bc-b809-4c05-b7ec-c5228be8fd92", "description": "", "name": "id", "allowedvalues": [], "format": "", "required": "true", "type": "Long" }], "apierrors": [ { "jsondocId": "e68ec826-19bf-4fd1-a962-9379b5abf920", "description": "Internal Server Error", "code": "500" }, { "jsondocId": "7ea15806-5691-4395-a399-e78a649314c1", "description": "Object not found", "code": "404" }, { "jsondocId": "480ad08e-12b1-437b-b607-7d17f3117d23", "description": "Validation failed", "code": "406" } ], "verb": "PUT", "description": "Update a member", "queryparameters": [], "path": "/api/members/{id}", "produces": ["application/json"], "methodName": "update" }, { "headers": [], "bodyobject": { "mapKeyObject": "", "jsondocId": "69b94b71-49b9-4ccc-92ba-9886f0eef37c", "mapValueObject": "", "map": "", "object": "member", "multiple": "Unknow" }, "jsondocId": "23d791cb-7486-40a9-ab13-c1b508f5401c", "consumes": ["application/json"], "response": { "mapKeyObject": "", "jsondocId": "c79e2da0-c6cd-4d95-9c76-87136c236671", "mapValueObject": "", "object": "Member", "multiple": "false" }, "pathparameters": [{ "jsondocId": "02ab6571-6895-4754-9b85-30905319e40a", "description": "", "name": "id", "allowedvalues": [], "format": "", "required": "true", "type": "Long" }], "apierrors": [ { "jsondocId": "db19acaf-6abf-4f37-bf0c-b785ba260542", "description": "Internal Server Error", "code": "500" }, { "jsondocId": "2e5749c8-97b0-4be7-b21b-8341fc2c5bb7", "description": "Object not found", "code": "404" }, { "jsondocId": "9f22892d-a926-4c0a-a548-4e0857257dc6", "description": "Validation failed", "code": "406" } ], "verb": "PUT", "description": "Update a member", "queryparameters": [], "path": "/api/members/{id}", "produces": ["application/json"], "methodName": "update" }, { "headers": [], "bodyobject": null, "jsondocId": "b8fe736d-a047-40e4-bc54-85061474f54f", "consumes": [], "response": { "mapKeyObject": "", "jsondocId": "411e65ed-57cd-4539-927e-d1729e63de0f", "mapValueObject": "", "object": "Member", "multiple": "false" }, "pathparameters": [{ "jsondocId": "848c060c-6ab8-4efb-bb3f-013b625035db", "description": "", "name": "id", "allowedvalues": [], "format": "", "required": "true", "type": "Long" }], "apierrors": [ { "jsondocId": "0183984f-5160-412b-afe0-2b8aecc4442e", "description": "Internal Server Error", "code": "500" }, { "jsondocId": "5bb6a59d-76af-4bbf-8933-08eeb36fd1e4", "description": "Object not found", "code": "404" } ], "verb": "GET", "description": "Get a member", "queryparameters": [], "path": "/api/members/{id}", "produces": ["application/json"], "methodName": "show" }, { "headers": [], "bodyobject": null, "jsondocId": "062c9adf-7c27-4f7d-a6a2-2fdbcb1aaa1a", "consumes": [], "response": { "mapKeyObject": "", "jsondocId": "e184d7c0-16fd-4933-9031-76cf84dcdc9e", "mapValueObject": "", "object": "Member", "multiple": "false" }, "pathparameters": [{ "jsondocId": "f995bf5e-42e5-41b1-a382-80eea925aa15", "description": "", "name": "id", "allowedvalues": [], "format": "", "required": "true", "type": "Long" }], "apierrors": [ { "jsondocId": "28c5381e-c646-4f40-bb67-7508fb470c07", "description": "Internal Server Error", "code": "500" }, { "jsondocId": "192b0247-2f34-4aba-a0ae-5545958a27b1", "description": "Object not found", "code": "404" } ], "verb": "GET", "description": "Get a member", "queryparameters": [], "path": "/api/members/{id}", "produces": ["application/json"], "methodName": "show" }, { "headers": [], "bodyobject": null, "jsondocId": "482cf970-ab10-48c1-b614-11cb1456f762", "consumes": [], "response": { "mapKeyObject": "", "jsondocId": "cf57cc51-56c5-4058-8e5c-4c87f5b8786c", "mapValueObject": "", "object": "List", "multiple": "MemberTag" }, "pathparameters": [], "apierrors": [ { "jsondocId": "cfbde57c-4393-4229-9503-84a50b9e3b9c", "description": "Internal Server Error", "code": "500" }, { "jsondocId": "bcb850c2-6816-4c5f-8a2e-4a56aa7e269f", "description": "Object not found", "code": "404" } ], "verb": "GET", "description": "List available tags for members", "queryparameters": [], "path": "/api/members/tags", "produces": ["application/json"], "methodName": "listTags" } ], "jsondocId": "d94b204a-79ff-4db6-8cb8-52b202508991", "description": "Methods for managing members", "name": "Member services" } ], "objects": [], "version": "0.1.1" }
Strange, still cannot reproduced... I'v try with your doc code in the sample project.
The "pseudocode" for method doc is:
FOR EACH controller in Controllers
IF controller has @RestApi
FOR EACH method in controller.methods
IF method has @RestApiMethod
EXTRACT_DATA()
ADD_TO_METHOD_LIST()
I don't see where you may have a method twice in the list.
If you can grive me a grails project (a new simple project with this bug or your project if Opensource), it would help.
Thanks
Just a me too. I have the same issue with one of my controllers showing methods more than once. The method that does not take any parameters, shows up one. The other methods that take parameters all show up twice. Another controller that has methods with parameters does NOT duplicate them.
Could you try a clean (or clean-all) after a rest-api-doc?
Tried grails clean, grails rest-api-doc, grails clean with the same results. Odd it is only one of 3 controllers that has duplicates. I'm using grails 2.3.4.
me too.
create a simple Person with a firstName and lastName. annotate as documented
generate a Person controller annotate the class level, and only the index method
run grails rest-api-doc
index method is duplicated in the json api file:
{ "basePath": "/restApiTest", "apis": [{ "methods": [ { "headers": [], "bodyobject": null, "jsondocId": "47f70062-4d0c-40c9-a575-579782c82a11", "consumes": [], "response": { "mapKeyObject": "", "jsondocId": "33cf22f7-dfc4-4df2-bc4b-d6241b5cfb5e", "mapValueObject": "", "object": "person", "multiple": "Unknow" }, "pathparameters": [], "apierrors": [], "verb": "GET", "description": "get the collection of all persons", "queryparameters": [], "path": "/person.json", "produces": [ "xml", "json" ], "methodName": "index" }, { "headers": [], "bodyobject": null, "jsondocId": "21e17ea9-e9da-4363-9356-0b8ae8dfaa15", "consumes": [], "response": { "mapKeyObject": "", "jsondocId": "6df43cea-ea7f-4247-9eb1-2c58d92900be", "mapValueObject": "", "object": "person", "multiple": "Unknow" }, "pathparameters": [], "apierrors": [], "verb": "GET", "description": "get the collection of all persons", "queryparameters": [], "path": "/person.json", "produces": [ "xml", "json" ], "methodName": "index" } ], "jsondocId": "12fdcc0f-8f5c-4614-af86-b1ddde28056a", "description": "person service", "name": "person service" }], "objects": [{ "jsondocId": "a31e056e-ce2a-4d76-b582-3cd5613d753a", "description": "A person identity", "name": "person", "fields": [ { "jsondocId": "d456a206-dca2-4023-a5a5-54fa86c1265d", "description": "Persons last name", "presentInResponse": true, "mandatory": true, "name": "firstName", "allowedvalues": null, "useForCreation": true, "format": null, "defaultValue": null, "type": "String", "multiple": "false" }, { "jsondocId": "f350d92a-927b-4a66-86d5-05554b3fef57", "description": "Persons first name", "presentInResponse": true, "mandatory": true, "name": "lastName", "allowedvalues": null, "useForCreation": true, "format": null, "defaultValue": null, "type": "String", "multiple": "false" } ] }], "version": "0.1.1" }
package com.tksoftware
import static org.springframework.http.HttpStatus.*
import grails.transaction.Transactional import org.restapidoc.annotation.RestApi import org.restapidoc.annotation.RestApiMethod import org.restapidoc.pojo.RestApiVerb
@Transactional(readOnly = true) @RestApi(name='person service', description='person service') class PersonController {
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
static responseFormats = ['xml', 'json']
@RestApiMethod(
description='get the collection of all persons',
listing=true,
verb=RestApiVerb.GET,
produces=['xml', 'json']
)
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond Person.list(params), model:[personInstanceCount: Person.count()]
}
... Other non-annotated methods }
Thanks for the full sample. It seems that without the parameter (Integer max), its better. I will invastigate this, a new realease should be available shortly.
I just noticed also that getting the jsondoc report behind a firewall is not possible because the jquery.js is being retrieved directly from googleapis instead of from a local js directory
The duplication bug should be fix now in the new release (1.1.2)