Java Jersey project using following Swagger Core:
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
<version>2.0.2</version>
</dependency>
the document link goes to "openapi.json". Swagger-UI dist ver 3.20.5 is downloaded from here. Java code is like this:
#Path("/auth")
public class TestConttroller {
#GET
#Path("/{id}")
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response testGet(
#DefaultValue("") #HeaderParam("Authorization") String a,
#DefaultValue("") #PathParam("id") String id)
{
return Response.ok().build();
}
When sending request from Postman everything works. But when from following Swagger-UI, the header-param string "a" is an empty string while the path-param string is good. The part in openapi.json is here:
"paths" : {
"/auth/{id}" : {
"get" : {
"operationId" : "testGet",
"parameters" : [ {
"name" : "Authorization",
"in" : "header",
"schema" : {
"type" : "string",
"default" : ""
}
}, {
"name" : "id",
"in" : "path",
"required" : true,
"schema" : {
"type" : "string",
"default" : ""
}
} ],
"responses" : {
"default" : {
"description" : "default response",
"content" : {
"application/json" : { },
"application/xml" : { }
}
}
}
}
}
Check with WireShark found the header is not in request at all. Should the problem in Swagger-UI?
#HeaderParam("Authorization") is like a keyword of HTTP? when I used other name like "Auth" then it works.
Related
I want to define "default" response of an operation with #ApiResponse annotation.
I'm using swagger annotations 1.5.x and want to generate something like this (look at default response):
"get" : {
...
"responses" : {
"200" : {
"description" : "successful operation",
"schema" : {
"type" : "array",
"items" : {
"$ref" : "#/definitions/Address"
}
}
},
"default" : {
"description" : "unsuccessful operation",
"schema" : {
"$ref" : "#/definitions/ErrorResponse"
}
}
},
...
}
But I don't know how to do that, because #ApiResponse(code = ...) annotation expects only numbers not Strings.
My Java code:
...
#ApiResponses(value = {
#ApiResponse(code = 200, message = "successful operation", response = Address.class, responseContainer = "List"),
#ApiResponse(code = "default", message = "unsuccessful operation", response = ErrorMessage.class),
...})
public Response getAllAddresses() throws SQLException {
...
}
So is there any way to specify "default" ApiResponse in Swagger annotations 1.5.x?
I'm using Spring Boot with spring-cloud-contract-wiremock and com.github.tomakehurst.wiremock dependencies.
My wiremock definitions are stored in json files. Like that:
directoryA/mappings/detail-mapping-123.json:
{
"request" : {
"urlPath" : "/detail/123",
"method" : "GET"
},
"response" : {
"status" : 200,
"bodyFileName" : "detail.json",
"headers" : {
"Content-Type" : "application/json;charset=UTF-8"
}
}
}
directoryA/__files/detail.json:
{
"id": "123",
"name": "name-123"
}
directoryB/mappings/search-mapping-123.json:
{
"request" : {
"urlPath" : "/service/usa/search",
"queryParameters" : {
"query": {
"equalTo": "123"
}
},
"method" : "GET"
},
"response" : {
"status" : 200,
"bodyFileName" : "search-123.json",
"headers" : {
"Content-Type" : "application/json;charset=UTF-8"
}
}
}
directoryB/__files/search-123.json:
{
"count": 1,
"units": [
{
"name": "A123"
}
]
}
I have standard JUnit test class which is annotated with:
#AutoConfigureWireMock(stubs = {"classpath:/directoryA/mappings", "classpath:/directoryB/mappings"},
files = {"classpath:/directoryA", "classpath:/directoryB"},
port = 18081)
This files looks like are recognized correctly by wiremock and all definitions are parsed correctly, but the problem is with assigning correct body file to request:
When application try to execute request:
GET http://localhost:18081/service/usa/search?query=123 HTTP/1.1
Then I'm getting error:
java.lang.RuntimeException: java.io.FileNotFoundException: /home/my-project-dir/target/test-classes/directoryA/__files/search-123.json (Not found such file or directory)
So... The problem is that wiremock search for file defined in bodyFileName part of mapping definition (directoryB/mappings/search-mapping-123.json) in directory directoryA instead of directoryB, from where mapping file was used. If there will be used
/home/my-project-dir/target/test-classes/directoryB/__files/search-123.json
then everything should work fine...
Does somebody had similar problem? I'm not sure if this is a bug in my configuration or in wiremock library.
Try to exclude the "stubs" and "files" arguments from annotation #AutoConfigureWireMock, and put your mappings/files in src/test/resources, wiremock gets by default from these path
I am using Swagger Core 2.0 to generate openAPI 3.0 definition files and
I am having trouble to disable "security" for a particular endpoint.
I have my securitySchemes and root security element defined:
{
"openapi" : "3.0.1",
"security" : [ {
"JWT" : [ ]
} ],
"paths" : {
"/auth" : {
"post" : {
"summary" : "authenticate user",
"operationId" : "authenticate",
"requestBody" : {
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/AuthenticationRequest"
}
}
}
},
"responses" : {
"200" : {
"description" : "when user is successfully authenticated",
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/AuthenticateUserOutput"
}
}
}
},
"401" : {
"description" : "when email/password not valid or user is blocked/inactive"
}
}
}
},
},
"components" : {
"schemas" : {
"AuthenticateUserOutput" : {
"type" : "object",
"properties" : {
"token" : {
"type" : "string"
},
"lastLoginAt" : {
"type" : "string",
"format" : "date-time"
},
"lastProjectId" : {
"type" : "string"
}
}
},
...,
"AuthenticationRequest" : {
"required" : [ "email", "password" ],
"type" : "object",
"properties" : {
"email" : {
"type" : "string"
},
"password" : {
"type" : "string"
}
}
}
},
"securitySchemes" : {
"JWT" : {
"type" : "http",
"scheme" : "bearer",
"bearerFormat" : "JWT"
}
}
}
}
According to OPEN API 3 spec https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#securityRequirementObject i shall be able to override global "security requirement" for an individual operation. I would like to "disable" JWT security for a few operations and according to https://github.com/OAI/OpenAPI-Specification/blob/3.0.1/versions/3.0.1.md#securityRequirementObject it can be done:
To remove a top-level security declaration, an empty array can be used.
Unfortunately I am struggling to define "empty security array" on Operation level using annotations...
I tried to specify
security = {}
or
security = #SecurityRequirement(name ="")
but no security element within operation is generated at all....
Any idea ?
Below is my java code (i use for swagger dropwizard integration) that allows one to have SecurityScheme and root level security defined
Info info = new Info()
.title("someTitle")
.description("some description")
.version("1.0")
SecurityScheme jwtSecurity = new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.name("Authorization")
.in(SecurityScheme.In.HEADER)
.scheme("bearer")
.bearerFormat("JWT");
String securitySchemaName = "JWT";
OpenAPI oas = new OpenAPI()
.info(info)
.components(new Components().addSecuritySchemes(securitySchemaName, jwtSecurity))
.addSecurityItem(new SecurityRequirement().addList(securitySchemaName));
SwaggerConfiguration oasConfig = new SwaggerConfiguration()
.openAPI(oas)
.prettyPrint(true)
.resourcePackages(Stream.of("my.resources.package")
.collect(Collectors.toSet()));
environment.jersey().register(new OpenApiResource()
.openApiConfiguration(oasConfig));
Then on a few dedicated endpoints i would like to disable security, so i am trying with:
#POST
#Operation(
summary = "authenticate user",
responses = {
#ApiResponse(responseCode = "200", description = "when user is successfully authenticated",
content = #Content(schema = #Schema(implementation = AuthenticateUserOutput.class))),
#ApiResponse(responseCode = "401", description = "when email/password not valid or user is blocked/inactive"),
}
,security = what to put here ?
)
if you want to do it in yml swagger hub style you can put
security: []
in that endpoint after request body, So swagger considers it as no auth for that particular path or endpoint.
According to a comment over on the OpenAPI-Specifiction GitHub project. It should be possible.
Did you try this?
security: [
{}
]
I had the same problem, on a Java SpringBoot webapp (dependency org.springdoc:springdoc-openapi-ui:1.5.2). As per this answer, I solved it adding an empty #SecurityRequirements annotation on the operation. For example:
#POST
#SecurityRequirements
#Operation(
summary = "authenticate user",
responses = {
#ApiResponse(responseCode = "200", description = "when user is successfully authenticated",
content = #Content(schema = #Schema(implementation = AuthenticateUserOutput.class))),
#ApiResponse(responseCode = "401", description = "when email/password not valid or user is blocked/inactive"),
} )
)
I have /studentCourses endpoint on the server (built with Spring Data REST) which returns the following content:
{
"_embedded" : {
"studentCourses" : [
{
"uid" : "5f23abe9-b24e-4e76-86b0-d539950a0a41",
"registrationDate" : "7/23/2016",
"_links" : {
"self" : {
"href" : "http://localhost:8080/studentCourses/5f23abe9-b24e-4e76-86b0-d539950a0a41"
},
"studentCourse" : {
"href" : "http://localhost:8080/studentCourses/5f23abe9-b24e-4e76-86b0-d539950a0a41"
},
"course" : {
"href" : "http://localhost:8080/studentCourses/5f23abe9-b24e-4e76-86b0-d539950a0a41/course"
},
"student" : {
"href" : "http://localhost:8080/studentCourses/5f23abe9-b24e-4e76-86b0-d539950a0a41/student"
}
}
},
{
...
},
...
]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/studentCourses"
},
"profile" : {
"href" : "http://localhost:8080/profile/studentCourses"
}
},
"page" : {
...
}
}
And the following client code:
class StudentCourseDTO {
String uuid;
String registrationDate;
StudentDTO student; // contains uuid, firstName, lastName, etc.
CourseDTO course; // contains uuid, name, etc.
// getters, setters
}
RestTemplate restTemplate() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jackson2HalModule());
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MappingJackson2HttpMessageConverter messageConverter =
new MappingJackson2HttpMessageConverter();
messageConverter.setObjectMapper(objectMapper);
messageConverter.setSupportedMediaTypes(Arrays.asList(MediaTypes.HAL_JSON));
return new RestTemplate(Arrays.asList(messageConverter));
}
...
Collection<StudentCourseDTO> studentCourses = restTemplate().exchange(
"http://localhost:8080/studentCourses",
HttpMethod.GET, null,
new ParameterizedTypeReference<PagedResources<StudentCourseDTO>>() {})
.getBody().getContent();
The problem is that StudentCourseDTO.student and StudentCourseDTO.course are always null, but StudentCourseDTO.uuid and StudentCourseDTO.registrationDate are retrieved correctly from the server.
Anyone has an idea what I have missed?
I think there must be someway to tell RestTemplate to automatically follow the links in the returned content like student and course in the example above, but I haven't found a way to do this.
Just because there are links that does not mean they are automatically followed.
I would change the StudentCourseDTO to:
class StudentCourseDTO {
String uuid;
String registrationDate;
}
And then you would deserialize the response to a
PagedResources<Resource<StudentCourseDTO>> studentCourses = restTemplate().exchange(
"http://localhost:8080/studentCourses",
HttpMethod.GET, null,
new ParameterizedTypeReference<PagedResources<Resource<StudentCourseDTO>>>() {})
.getBody().getContent();
For each Resource<StudentCourseDTO> you can then follow the links for studentand course, e.g. by using the RestTemplate to retrieve the resources.
Of course this gives you two additional calls per response item - but the only way to avoid this is to change the service to embed this information in the list resource.
I have this query used with Exists API from elasticsearch (1.4.4) :
curl -XPOST 'http://elasticsearch:9200/_search/exists' -d '
{
"query": {
"filtered": {
"query": {
"match_phrase": {
"message": "2014-12-04 00:00:01 CET Tx[XXXXXXXX] cmd[INSERT] PID[XXXX] DB[XXXXX] LOG: some log info here ;-) \r"
}
},
"filter": {
"term" : {
"some_field" :"some_value"
}
}
}
}
}'
This works fine (return true when it has to be) but when I tried to do the same with java API like this :
Client client = this.createClient();
QueryBuilder queryBuilder = QueryBuilders.filteredQuery(
QueryBuilders.matchPhraseQuery("message", "the same message"),
FilterBuilders.termFilter("some_field", "some value")
);
System.out.println(queryBuilder.toString());
ExistsResponse response = client.prepareExists("existsMessage")
.setTypes(type)
.setIndicesOptions(IndicesOptions.fromOptions(true, true, true, false))
.setQuery(queryBuilder).execute().actionGet();
System.out.println(response.exists());
client.close();
But the result is always false! So I print the request build by the and it's different than want I wanted. So is there a way to do exactly my first request from source json or other way using api builders?
Edit :
The output of queryBuilder.toString()) :
{
"filtered" : {
"query" : {
"match" : {
"message" : {
"query" : "the same message\r",
"type" : "phrase"
}
}
},
"filter" : {
"term" : {
"some field" : "some value"
}
}
}
}