I currently have the problem that I am looking for an artifact in Jenkins. If this artifact can not be found, then a 404 should come back. So far this works quite well. Unfortunately I get no message and only the ErrorCode 404 back. I would like to return a message with more information.
Here's my code.
Endpoint:
#GET
#Path(API_RESOURCE_IMAGE_REPORT)
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.TEXT_HTML)
#Operation(summary = "", description = "")
#APIResponses(
value = {
#APIResponse(
responseCode = "200",
description =
"Request successful",
content = #Content(mediaType = MediaType.TEXT_HTML)),
#APIResponse(
responseCode = "404",
description = "Resource not found ",
content =
#Content(
mediaType = MediaType.APPLICATION_JSON,
schema = #Schema(implementation = NotFoundException.class))),
})
public Response getReport(#Parameter(
description = "",
required = true)
#PathParam("imageName") final String imageName,
#Parameter(description = "", required = true)
#PathParam("tag") final String tag,
#Parameter(description = "")
#PathParam("type") String type
) {
InputStream report = jenkinsClient.getReport(imageName, tag, type);
return Response.status(HttpURLConnection.HTTP_ACCEPTED).entity(report).build();
}
Jenkinsclient:
public InputStream getReport(final String imageName, final String tag, final String type) throws NotFoundException {
try {
final int lastSuccessfulBuildnumber = jenkinsClient.api().jobsApi().jobInfo(imageName, tag).lastSuccessfulBuild().number();
LOG.info("Last successful buildnumber: " + lastSuccessfulBuildnumber);
final InputStream report = jenkinsClient.api().jobsApi().artifact(imageName, tag, lastSuccessfulBuildnumber, Objects.equals(type, "image") ? "trivy_image_report.html" : "trivy_Dockerfile_report.html");
if (report == null) {
throw new NotFoundException("No dockerfile or image report found");
}
return report;
} catch (Exception e) {
throw new NotFoundException("No dockerfile or image scan report found");
}
}
I expected a 404 with a the message "No dockerfile or image scan report found". But i got only 404 without a message when i dont find an artefact. I used the "javax.ws.rs.NotFoundException" for NotFoundException.
Thanks for help
Thanks to Nikos Paraskevopoulos in the comments.
Ive added the response status in the Exception like this:
throw new NotFoundException(Response.status(HttpURLConnection.HTTP_NOT_FOUND).entity("your message").build());
this worked fine and i have the message in the response body
Related
I am currently trying to return an input stream via my API. The input stream contains an html file that I previously fetch from Jenkins via the Cdancy Jenkinsclient via the input stream. I want to pass this html through my endpoint. If I enter Json as #Produce, then the HTML content comes with the note that the JSON can not be parsed. If I specify another MediyType, then a 406 comes back. Is it even bestpractise to return an inputstream or should I transform it into an outputstream first?
This is my Code:
Endpoint
#GET
#Path(API_RESOURCE_IMAGE_REPORT)
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_OCTET_STREAM)
#Operation(summary = "", description = "")
#APIResponses(
value = {
#APIResponse(
responseCode = "200",
description =
"",
content = #Content(mediaType = MediaType.APPLICATION_JSON)),
#APIResponse(
responseCode = "400",
description = "",
content =
#Content(
mediaType = MediaType.APPLICATION_JSON,
schema = #Schema(implementation = ErrorResponseDO.class))),
})
public Response getReport(#Parameter(
description = "",
required = true)
#PathParam("imageName") final String imageName,
#Parameter(description = "", required = true)
#PathParam("tag") final String tag,
#Parameter(description = "")
#PathParam("type") String type
) throws ApplicationException, IOException {
InputStream report = jenkinsClient.getReport(imageName, tag, type);
return Response.status(HttpURLConnection.HTTP_ACCEPTED).entity(report).build();
}
Jenkinsclient:
public InputStream getReport(final String imageName, final String tag, final String type) throws ApplicationException {
try {
final int lastSuccessfulBuildnumber = jenkinsClient.api().jobsApi().jobInfo(imageName, tag).lastSuccessfulBuild().number();
LOG.info("Last successful buildnumber: " + lastSuccessfulBuildnumber);
final InputStream report = jenkinsClient.api().jobsApi().artifact(imageName, tag, lastSuccessfulBuildnumber, Objects.equals(type, "image") ? "trivy_image_report.html" : "trivy_Dockerfile_report.html");
if (report == null) {
throw new NotFoundException();
}
return report;
} catch (Exception e) {
throw new NotFoundException();
}
}
Output:
Output is 406 everytime (TEXT_HTML, OCTET_STREAM, TEXT_PLAINE).
Only with #Produces(MediaType.APPLICATION_JSON) it is successfull with the html code bud with the message: json cant be parsed.
Thanks for your help
Like VGR stated. Problem was the caller which was not using text/html. Ive tested in swaggerui and set it to "text/html". Works as expected. Was application/json beforen and the reason for working only with application json as produce annoation.
I try to send an image with some attributes from flutter to spring boot endpoint, but spring boot not received the image at all and it gives me this error:
Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'image' is not present]
here is my code:
Spring boot
#PostMapping("")
public ResponseEntity<UsersEntity> createNewUser(#RequestParam(value = "image") MultipartFile image, UsersEntity user) {
UsersEntity response = userService.createUser(user, image);
return ResponseEntity.ok(response);
}
Flutter
var postUri = Uri.parse("http://localhost:8080/v1");
var request = new http.MultipartRequest("POST", postUri);
request.fields['fName'] = firstNameController.text;
request.fields['lName'] = lastNameController.text;
if(image != null) {
request.files.add(http.MultipartFile.fromBytes(
'image', image!, contentType: MediaType.parse('multipart/form-data')));
}
Map<String, String> headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Headers": "Origin,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,locale",
"content-type": "application/json"};
request.headers.addAll(headers);
request.send().then((response) {
if (response.statusCode == 200) {
print("Success!");
} else {
print('Error!');
}
});
My service work very well with Postman, any idea how can I solve this issue?
Solution
Credit to this https://github.com/flutter/flutter/issues/37311#issuecomment-516967285
I just add filename and every thing work fine:
request.files.add(http.MultipartFile.fromBytes(
'image', image!,
contentType: MediaType.parse('multipart/form-data'),
filename: 'test.jpg'));
var uri = Uri.parse('$baseUrl/services/selfemployment/check-confirmation-code');
var request = new http.MultipartRequest("POST", uri);
request.headers.addAll(baseHeader);
request.fields['example'] = example;
request.fields['image'] = image;
http.Response response = await http.Response.fromStream(await request.send());
print('Uploaded! ${response.body} ++ ${response.statusCode}');
Is it in some way possible that an exception thrown from a rest service is returned as JSON? I have a JAX-RS Rest Service where I would like to achieve this. Basically, I am returning a zip file as a Response from our API which is working as expected but when I am getting any exception the same I want to return it as a JSON response from API. Is there any way to achieve this:
#RolesAllowed({"admin", "analyst", "investigator", "supervisor", "data_scientist", "quality_assurance", "executive", "confidential"})
#Path("/download/{id}")
#GET
#Produces("application/zip")
#Consumes(MediaType.APPLICATION_JSON)
#ApiOperation(value = "Returns a List.", notes = "")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "", response = VO.class),
#ApiResponse(code = 404, message = "", response = ErrorMessage.class),
#ApiResponse(code = 500, message = "", response = ErrorMessage.class) })
public Response downloadFile(
#HeaderParam("x-access-token") String jwtToken,
#Context SecurityContext sec,
#Context final HttpServletResponse response,
#PathParam("id") String id)
throws Exception {
ErrorMessage errorMessage=new ErrorMessage();
ResponseBuilder response1=null;
try{
if (id == null) {
throw new BusinessException("Id should not be empty.Please provide Id.");
}
String File=DownloadUtil.exportToFile(wl);
byte[] bytes =Files.readAllBytes(Paths.get(File));
ByteArrayOutputStream out = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream( out );
zipOut.putNextEntry( new ZipEntry( File ) );
zipOut.write(bytes);
zipOut.closeEntry();
zipOut.close();
response1 = Response.ok(out.toByteArray());
response1.header("Content-Disposition", "attachment; filename=list.zip");
}
catch (Exception msg)
{
errorMessage.setCode(422);//your custom error code
errorMessage.setMessage("Error occured");//custom status
return Response.status(200).entity(errorMessage).build();
}
return response1.build();
}
Using the above error message technique I am getting the following exception and in the response getting [Object Blob]:
No message body writer has been found for class com.test.exception.ErrorMessage, ContentType: application/zip
I am developing jersey endpoints and I have to do the integration test for this endpoints, my doubt is how can I make the unit test for this endpoint without adding more dependencies to the pom or additional libraries, because it is a restriction. There is a way to achieve that? I am using junit version 5. This is an example of my endpoint. I was using jerseyTest but I had to revert my changes, because of the restriction:
#GET
#Path("/")
#ApiResponses(value = {
#ApiResponse(code = SC_OK, response = HorasPaginatedResult.class,
message = "Successfully retrievedHoras from Labor Service"),
#ApiResponse(code = SC_BAD_REQUEST, response = ErrorMessage.class, message = "The request was malformed or missing a required field"),
#ApiResponse(code = SC_INTERNAL_SERVER_ERROR, response = ErrorMessage.class, message = "There was an issue processing the request and the server has failed out of the action"),
})
#ApiOperation(value = "Used to query the time service for timeclocks.",
response = HorasPaginatedResult.class,
tags = "Horas",
nickname = "get-Horas.all")
public PaginatedResult<Horas> getHorasAll(
#Nullable #ApiParam("the token to the next page of results") #QueryParam("token") String token,
#Nullable #ApiParam(value = "the field to sort by - this may through a 500 error if the index does not exsist", example = "timestamp") #QueryParam("sortBy") String sortBy,
#Nullable #ApiParam("boolean to determine which direction the sort should be in") #QueryParam("sortAscending") Boolean sortAscending,
#Nullable #ApiParam("the maximum number of 'records' to return per page") #QueryParam("recordLimit") Integer recordLimit,
#Nullable #ApiParam(value = "object", example = "%7B%22field%22%") #QueryParam("expression") List<Query.Expression> expressions) {
Query query;
if (token != null) {
query = new Query(token);
} else {
query = new Query(sortBy, recordLimit, sortAscending);
if (expressions != null) {
expressions.forEach(query.getExpressions()::add);
}
}
logger.info("creating query of {}", query);
return HorasService.getHoras(query);
}
private static class HorasPaginatedResult extends PaginatedResult<BanquetLaborHoras> {
}
Any ideas?
I'm trying to document an API method that will receive a file and two parameters as int. Using swagger editor I was able to describe what I want, but couldn't replicate that using annotations.
This is what I draw on swagger editor
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
flow:
type: integer
environment:
type: integer
file:
type: string
format: binary
required: true
If I use consumes = MediaType.MULTIPART_FORM_DATA I get the params. And if I use consumes = MediaType.APPLICATION_OCTET_STREAM I get the file to upload.
#Operation(summary = "Unpack Files",
description = "Receives a packed zip or gzip file with xml files inside or receives xml files",
security = #SecurityRequirement(name = "apiKey"),
responses = {
#ApiResponse(responseCode = "201", description = "Created"),
#ApiResponse(responseCode = "400", description = "Something Went Wrong"),
#ApiResponse(responseCode = "401", description = "Unauthorized"),
#ApiResponse(responseCode = "503", description = "Service Unavailable")
},
requestBody = #RequestBody(
content = #Content(
mediaType = MediaType.MULTIPART_FORM_DATA,
schema = #Schema(implementation = Document.class, format = "binary"),
encoding = #Encoding(
name = "file",
contentType = "application/xml, application/zip, application/gzip"
)
),
required = true
)
)
#Post(value = "/unpack", consumes = MediaType.APPLICATION_OCTET_STREAM)
public Single<HttpResponse<String>> upload(StreamingFileUpload file, int flow, int environment) throws IOException {
return Single.just(new Document(file.getFilename(), environment, flow))
.flatMap(DocumentValidation::validateDocumentExtension)
.doOnError(throwable -> {
log.error("Validation exception: {}", throwable.getMessage());
exception = throwable.getMessage();
})
.doOnSuccess(doc -> {
log.info("File saved successfuly");
File tempFile = File.createTempFile(file.getFilename(), "temp");
file.transferTo(tempFile);
})
.map(success -> {
if (exception != null || !exception.equals("")) {
return HttpResponse.<String>status(HttpStatus.CREATED).body("Uploaded");
} else {
return HttpResponse.<String>status(HttpStatus.SERVICE_UNAVAILABLE).body(exception);
}
}
);
}
Thanks in advance.
Looks like missing #QueryValue
From documentation 6.4 Simple Request Binding:
Bindings from a request URI variable or request parameter | #QueryValue String myParam
From documentation 6.19 File Uploads:
The method is set to consume MULTIPART_FORM_DATA
The method parameters match form attribute names. In this case the file will match for example an
The StreamingFileUpload.transferTo(java.lang.String) method is used to transfer the file to the server.
Kotlin simple:
#Controller
class SomeController {
#Post(value = "/", consumes = [MediaType.MULTIPART_FORM_DATA])
fun upload(file: StreamingFileUpload,
#QueryValue flow: Int,
#QueryValue environment: Int): Single<HttpResponse<String>> {
val tempFile = File.createTempFile(file.filename, "temp")
return Single.fromPublisher(file.transferTo(tempFile))
.map { success ->
if (success) {
HttpResponse.ok("Uploaded");
} else {
HttpResponse.status<String>(HttpStatus.CONFLICT)
.body("Upload Failed")
}
}
}
}