1

So I have newly upgraded to Swagger 2 from 1.x, and am experiencing an odd issue. One of my APIs is getting an incorrect content-type injected into the header and I have no idea where from, you can see below in the SwaggerJSON, The DELETE function even says it consumes application/json, but the CURL(copied from inspect panel) for it sends 'Content-Type: text/plain;charset=UTF-8'. I have provided the CREATE function as a cursory example to show that otherwise the similar apis work fine. I think this is an issue with swagger-js-codegen because if I put the same request into the api-docs it works fine, or of course my Java, or somewhere somehow my content-type header is getting set, but i have no idea how or where. Am I missing something? The API acts the same whether or not my JAVA claims 'consume = "application/json"' or not.

Swagger JSON

{
  "/api/entities/{id}/labels": {
    "delete": {
      "consumes": [
        "application/json"
      ],
      "operationId": "deleteEntityLabel",
      "parameters": [
        {
          "default": "16_appiniteDev",
          "description": "The id of the entity to be edited",
          "in": "path",
          "name": "id",
          "required": true,
          "type": "string"
        },
        {
          "description": "The label/labels to be deleted",
          "in": "body",
          "name": "labels",
          "required": true,
          "schema": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        }
      ],
      "produces": [
        "application/json"
      ],
      "responses": {
        "200": {
          "description": "OK",
          "schema": {
            "$ref": "#/definitions/ResponseEntity"
          }
        },
        "204": {
          "description": "No Content"
        },
        "401": {
          "description": "Unauthorized"
        },
        "403": {
          "description": "Forbidden"
        }
      },
      "summary": "Deletes Labels for Entities",
      "tags": [
        "entity-resource"
      ]
    },
    "post": {
      "consumes": [
        "application/json"
      ],
      "operationId": "createEntityLabel",
      "parameters": [
        {
          "default": "16_appiniteDev",
          "description": "The id of the entity to be edited",
          "in": "path",
          "name": "id",
          "required": true,
          "type": "string"
        },
        {
          "description": "The array of labels to be set",
          "in": "body",
          "name": "labels",
          "required": true,
          "schema": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        }
      ],
      "produces": [
        "application/json"
      ],
      "responses": {
        "200": {
          "description": "OK",
          "schema": {
            "$ref": "#/definitions/ResponseEntity"
          }
        },
        "201": {
          "description": "Created"
        },
        "401": {
          "description": "Unauthorized"
        },
        "403": {
          "description": "Forbidden"
        },
        "404": {
          "description": "Not Found"
        }
      },
      "summary": "Creates Labels for Entities",
      "tags": [
        "entity-resource"
      ]
    }
  }
}

DELETE
JAVA/SPRING
    /**
     * DELETE /entities/{id}/labels -> delete labels for an entity
     *
     * @param id
     * @param labels
     * @throws ServiceException
     */
    @RequestMapping(value = "/entities/{id}/labels", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE)
    @Timed
    @ApiOperation(value = "Deletes Labels for Entities", nickname = "deleteEntityLabel", consumes = "application/json")

    public ResponseEntity deleteLabels(
            @ApiParam(value = "The id of the entity to be edited", required = true, defaultValue = "16_appiniteDev") @PathVariable final String id,
            @ApiParam(value = "The label/labels to be deleted", required = true, defaultValue = "[\"label1\",\"label2\",\"label3\"]") @NotNull final @RequestBody String[] labels

    ) throws ServiceException {
        boolean isAppEntity = false;
        User user = userService.getUserWithAuthorities();
        String[] type = id.split("_");
        if (StringUtils.isNumeric(type[0]) && !type[1].startsWith(type[0])) {
            isAppEntity = true;

        }

        entityService.deleteTags(id, labels, user, isAppEntity);
        Map<String, String> response = new LinkedHashMap<>();
        response.put(Constants.RESPONSE_ENTITY_HEADER_MESSAGE,
                "Labels deleted successfully");
        return new ResponseEntity(response, HttpStatus.OK);
    }

CURL FROM APP
curl 'http://localhost:8080//api/entities/52_QA42/labels?cacheBuster=1472070679337' -X DELETE -H 'Pragma: no-cache' -H 'Origin: http://localhost:8080' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' -H 'Content-Type: text/plain;charset=UTF-8' -H 'Accept: application/json, text/plain, */*' -H 'Cache-Control: no-cache' -H 'x-auth-token: admin:1472097365429:8e6524e252e2aebb786b7738c44fe385' -H 'Referer: http://localhost:8080/' -H 'Cookie: NG_TRANSLATE_LANG_KEY=%22en%22' -H 'Connection: keep-alive' -H 'DNT: 1' --data-binary '["Bug13124"]' --compressed


CREATE
JAVA/SPRING
    /**
     * POST /entities/{id}/labels -> add labels for a non hadoop entity
     *
     * @param id
     * @param labels
     * @throws ServiceException
     */
    @RequestMapping(value = "/entities/{id}/labels", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    @Timed
    @ApiOperation(value = "Creates Labels for Entities", nickname = "createEntityLabel")
    public ResponseEntity addLabels(
            @ApiParam(value = "The id of the entity to be edited", required = true, defaultValue = "16_appiniteDev") @PathVariable final String id,
            @ApiParam(value = "The array of labels to be set", required = true, defaultValue = "[\"label1\",\"label2\",\"label3\"]") @NotNull final @RequestBody String[] labels)
            throws ServiceException {
        boolean isAppEntity = false;
        User user = userService.getUserWithAuthorities();
        String[] type = id.split("_");
        if (StringUtils.isNumeric(type[0]) && !type[1].startsWith(type[0])) {
            isAppEntity = true;

        }

        entityService.addTags(id, labels, user, isAppEntity);
        Map<String, String> response = new LinkedHashMap<>();
        response.put(Constants.RESPONSE_ENTITY_HEADER_MESSAGE,
                "Labels added successfully");
        return new ResponseEntity(response, HttpStatus.OK);
    }

CURL FROM APP
curl 'http://localhost:8080//api/entities/52_QA42/labels?cacheBuster=1472071851544' -H 'Pragma: no-cache' -H 'Origin: http://localhost:8080' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' -H 'Content-Type: application/json;charset=UTF-8' -H 'Accept: application/json, text/plain, */*' -H 'Cache-Control: no-cache' -H 'x-auth-token: admin:1472097365429:8e6524e252e2aebb786b7738c44fe385' -H 'Referer: http://localhost:8080/' -H 'Cookie: NG_TRANSLATE_LANG_KEY=%22en%22' -H 'Connection: keep-alive' -H 'DNT: 1' --data-binary '["test"]' --compressed

Any Ideas?

5
  • Can you please clarify what is the "app"? Do you mean swagger-ui? And for swagger-js-codegen, are you talking about something that is produced from the swagger-codegen project, or are you talking about swagger-js? Commented Aug 24, 2016 at 22:19
  • swagger-js-codegen is the swagger-codegen FOR swagger-js. github.com/wcandillon/swagger-js-codegen Commented Aug 25, 2016 at 13:13
  • @trudesign you may consider using swagger codegen to generate the JS client (or API clients in Typescript, PHP, Ruby, Java, etc). Commented Aug 26, 2016 at 8:21
  • @wing328 to be honest, I couldn't understand how swagger-codegen worked, and swagger-js-codegen is an approved plugin to do the angular swagger-codegen conversion for me. I need to figure out how to get swagger-js-codegen to actually write the request content-type, it seems to ignore the 'consumes' property of the swagger json file. Commented Aug 26, 2016 at 14:57
  • @trudesign thanks for the feedback. Installing java, mvn, etc so as to use swagger codegen may be pain to non-Java developers. Another way is to use editor.swagger.io or generating the SDKs online. If you need further assistance, pls let me know. Commented Aug 27, 2016 at 7:26

1 Answer 1

1

I haven't been able to nail down how or where it is setting that Content-Type, so I've fixed this in a brute force way: Created an interceptor to change the header content-type by force:

.factory('contentInterceptor', function ($rootScope, $q, $location, localStorageService, $cookies) {
    return {
        // Add authorization token to headers
        request: function (config) {
            config.headers = config.headers || {};
            config.headers['Content-Type'] = 'application/json';
            return config;
        }
    };
})

.config(function ($httpProvider) {
    $httpProvider.interceptors.push('contentInterceptor');
});

Works like a charm, and luckily doesn't affect any other of my API's as they ALL require Application/JSON except for the multipart form ones, but those explicitly get set and aren't affected by this interceptor.

**** UPDATE *****

I'm a dumb dumb and didn't realize I could've just put the following in my mustache template. This is the correct answer. It takes the proper 'consumes' and 'produces' properties and ensures the right headers are being sent.

{{#headers}}
    options.headers['{{&name}}'] = {{&value}};
{{/headers}}
Sign up to request clarification or add additional context in comments.

1 Comment

Note: this doesn't work as well as I thought it would. It doesn't override requests made with an $http call but still overrides swagger generated api calls. Not an optimal solution. Will update next week when I figure it out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.