Testing Dropwizard Resource's POST method - post

Hello I have the following resource class
#Path("/api")
#Api("My API")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class MyResource {
public MyResource() {
// assign some values in teh constructor
}
#POST
#Timed
#UnitOfWork
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#ApiOperation(
value = "",
response = Response.class)
#ApiResponses(
value = {#ApiResponse(code = 405, message = "Method not allowed"), #ApiResponse(code = 400,
message = "some custom mesage")})
public Response createMyObject(MyObject o, #Context UriInfo uriInfo)
throws JsonProcessingException {
}
And I am trying to unit test it using this
#Test
public void testCreate() throws JsonProcessingException {
Entity<?> entity = Entity.entity(myObjInstance, MediaType.APPLICATION_JSON_TYPE);
final Response response = resources.target("/api").request().post(entity);
}
This gives me a 404, I have verified that the resource is correctly registered. Also the GET methods in this resource work as expected. What am I doing wrong?

Related

How to customize the built-in MVC validation response format?

I'm using my own middleware to capture exceptions thrown in my API to format the response to the client. This includes things like checking for the dev env to send additional information and logging. This all works great but the built-in validation middleware responds with a different response format. I want to keep the functionality and just change what data is sent to the client and how it's formatted.
Currently it returns the default
{
"message": "Validation error(s)",
"details": [
"The value '35353535353535353535353535353535353535353535' is not valid."
]
}
You can customize the default response by using a BadResultObject in the InvalidaModelStateResponseFactory of the ApiBehaviorOptions class. As an example:
apiBehaviorOptions.InvalidModelStateResponseFactory = actionContext => {
return new BadRequestObjectResult(new {
Code = 400,
Request_Id = "Someuniqueid",
Messages = actionContext.ModelState.Values.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage)
});
Configured:
serviceCollection.PostConfigure<ApiBehaviorOptions>(apiBehaviorOptions =>
apiBehaviorOptions.InvalidModelStateResponseFactory = ...
);
Or you can send the response directly from the action you are using as well with your own custom validation error result class. For example:
public class ValidationError
{
[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
public string Field { get; }
public string Message { get; }
public ValidationError(string field, string message)
{
Field = field != string.Empty ? field : null;
Message = message;
}
}
public class ValidationResultModel
{
public string Message { get; }
public List<ValidationError> Errors { get; }
public ValidationResultModel(ModelStateDictionary modelState)
{
Message = "Validation Failed";
Errors = modelState.Keys
.SelectMany(key => modelState[key].Errors.Select(x => new
ValidationError(key, x.ErrorMessage)))
.ToList();
}
}
Then we can create our own IActionResult. Here:
public class ValidationFailedResult : ObjectResult
{
public ValidationFailedResult(ModelStateDictionary modelState)
: base(new ValidationResultModel(modelState))
{
StatusCode = StatusCodes.Status404...;
}
}
And update our ValidateModelAttribute by overriding the OnActionExecuting to perform actions before they are taken.
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new ValidationFailedResult(context.ModelState);
}
}
}
Sources:
Customize automatic response on validation error
https://www.jerriepelser.com/blog/validation-response-aspnet-core-webapi/

Swagger Authentication using Annotation

I am trying to have a basic Auth in my swagger ui.I am using Swagger 2.0.5 as a maven library.Using SwaggerConfig class to create docket Api and other configuration.
`
public class SwaggerConfig {
/**
* Every Docket bean is picked up by the swagger-mvc framework - allowing for multiple
* swagger groups i.e. same code base multiple swagger resource listings.
*/
#Bean
public Docket api() {
AuthorizationScope[] authScopes = new AuthorizationScope[1];
authScopes[0] = new AuthorizationScopeBuilder()
.scope("")
.build();
SecurityReference securityReference = SecurityReference.builder()
.reference("basicAuth")
.scopes(authScopes)
.build();
ArrayList<SecurityReference> reference = new ArrayList<SecurityReference>(1);
reference.add(securityReference);
ArrayList<SecurityContext> securityContexts = new ArrayList<SecurityContext>(1);
securityContexts.add(SecurityContext.builder().securityReferences(reference).build());
ArrayList<SecurityScheme> auth = new ArrayList<SecurityScheme>(1);
auth.add(new BasicAuth("basicAuth"));
Documentation Doc = new DocumentationBuilder().basePath("/swagger-ui.html").build();
return new Docket(DocumentationType.SWAGGER_2)
.securitySchemes(auth)
.securityContexts(securityContexts)
.select()
.apis(RequestHandlerSelectors.basePackage("com.toyota.tme.consumerapi.rest"))
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
/* #Bean
public Docket customDocket() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.regex("/v1/.*"))
.build();
}*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Consumer API")
.description("Azure based Consumer API.")
.contact("CarIT")
.build();
}
}`
My Issue is,I am using authorization annotatation in my rest service to enable Basic Auth.
#Api(value = "/ping", tags = "1.Ping", description = "API",authorizations = {#Authorization(value="basicAuth")})
#RestController
#RequestMapping("/api")
public class ping {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#RequestMapping(path = "/ping", method = RequestMethod.GET,
produces = MediaType.TEXT_HTML_VALUE)
#ApiOperation(value = "Ping service", httpMethod = "GET", response = String.class,
produces = "text/html", notes = "ping service",authorizations = {#Authorization(value="basicAuth")})
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success", response = String.class),
#ApiResponse(code = 400, message = "Bad request"),
#ApiResponse(code = 401, message = "Unauthorized"),
#ApiResponse(code = 404, message = "Not Found"),
#ApiResponse(code = 409, message = "Conflict"),
#ApiResponse(code = 503, message = "Dependent System(s) are unavailable"),
#ApiResponse(code = 500, message = "Unknown server Error occurred")})
public ResponseEntity<String> ping() {
this.logger.info("springframework api :Ping Request received for ConsumerAPI");
return new ResponseEntity<>(ApplicationConstants.Ping, HttpStatus.OK);
}
}
But this code is not working.I am not able to see any authorization asked by Swagger.Please need a help in this
Same for me. Solved this by moving the value authorizations from Api to ApiOperation annotation. Not beautiful but working.

swagger securityDefinition with Resteasy

I did configure swagger with an Application subclass and the beanConfig object, my securityDefinition must allow swagger ui to show de api_key field to allow authentication for all my services layer.
BeanConfig beanConfig = new BeanConfig();
beanConfig.setSchemes(new String[] { "http" });
beanConfig.setHost("192.168.4.9:8080");
beanConfig.setBasePath("/cjppa/rest");
beanConfig.setResourcePackage("com.cjppa.fpuna.backend.resources");
beanConfig.setScan(true);
beanConfig.setPrettyPrint(true);
io.swagger.models.Info info = new io.swagger.models.Info();
io.swagger.models.Contact contact = new io.swagger.models.Contact();
info.setVersion("1.0");
beanConfig.setInfo(info);
io.swagger.models.auth.ApiKeyAuthDefinition apikey = new
io.swagger.models.auth.ApiKeyAuthDefinition();
apikey.setName("x-token");
apikey.setIn(In.HEADER);
Swagger swagger = new Swagger().info(info);
swagger.securityDefinition("api_key", apikey);
beanConfig.configure(swagger);
the expected api_key comes in the "x-token" http header
I tried also to bring swagger into my resteasy webservice with using BasicAuthentification for some operations of my webservice. I imported swagger via maven in my pom.xml:
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jaxrs</artifactId>
<version>1.5.18</version>
</dependency>
In my Application class I configured the BeanConfig:
import javax.ws.rs.ApplicationPath;
import io.swagger.jaxrs.config.BeanConfig;
#ApplicationPath("/rest")
public class Application extends javax.ws.rs.core.Application{
public Application() {
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0");
beanConfig.setResourcePackage("de.mycompany.topic.ws");
beanConfig.setBasePath("/de.mycompany.topic.ws/rest/");
beanConfig.setScan(true);
}
}
The important thing is to configure the BasicAuthentification in an ReaderListener implementation via Annotations. basicAuth is an arbitrary name.
import io.swagger.annotations.BasicAuthDefinition;
import io.swagger.annotations.SecurityDefinition;
import io.swagger.annotations.SwaggerDefinition;
import io.swagger.jaxrs.Reader;
import io.swagger.jaxrs.config.ReaderListener;
import io.swagger.models.Swagger;
#SwaggerDefinition(securityDefinition = #SecurityDefinition(basicAuthDefinitions = {
#BasicAuthDefinition(key = "basicAuth")
}) )
public class SwaggerCustomizeDefinition implements ReaderListener {
#Override
public void beforeScan(Reader reader, Swagger swagger) {
}
#Override
public void afterScan(Reader reader, Swagger swagger) {
}
}
In MyRestService I annotate my operations that should be not usable without basic authentification. See here e.g. for saving customers:
#Api
#Path("/")
public class MyRestService {
private final static String UTF8 = ";charset=UTF-8";
#POST
#Path("/customer")
#Produces(MediaType.APPLICATION_JSON + UTF8)
#ApiOperation(
value = "Saves customer specified in the body",
notes = "note that appears in swagger ui",
authorizations = {
#Authorization(value = "basicAuth", scopes={})
})
#ApiResponses(value = {
#ApiResponse(code = 201, message = "customer created"),
#ApiResponse(code = 401, message = "Unauthorized"),
#ApiResponse(code = 404, message = "customer format not supported"),
})
public Response saveCustomer(
String content,
#BasicAuthDefinition(key = "basicAuth") #HeaderParam("Authorization") String authorization) {
// authorization
try {
if (!MyManager.isAuthorized(authorization)) {
return Response.status(Status.UNAUTHORIZED).build();
}
} catch (Exception e) {
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
}
//do the work, authorization was ok
}
}
That's it. I tried a lot of variations and this was the only one that works for me in whole. My main problem was, that the authorize button not appears in the ui and the lock above the single methods in the swagger ui was not clickable so that the basic authentification modal dialog not appears. With this implementation it works.
you can implements io.swagger.jaxrs.config.ReaderListener ,addSecurity in afterScan method . eg:
#SwaggerDefinition(securityDefinition = #SecurityDefinition(apiKeyAuthDefinitions = {
#ApiKeyAuthDefinition(in = ApiKeyAuthDefinition.ApiKeyLocation.HEADER, key = "token", name = "E-token"),
#ApiKeyAuthDefinition(in = ApiKeyAuthDefinition.ApiKeyLocation.HEADER, key = "userId", name = "E-userId"),
#ApiKeyAuthDefinition(in = ApiKeyAuthDefinition.ApiKeyLocation.HEADER, key = "corpId", name = "E-corpId") }) )
public class SwaggerCustomizeDefinition implements ReaderListener {
#Override
public void beforeScan(Reader reader, Swagger swagger) {
}
#Override
public void afterScan(Reader reader, Swagger swagger) {
swagger.addSecurity(new SecurityRequirement().requirement("token"));
swagger.addSecurity(new SecurityRequirement().requirement("userId"));
swagger.addSecurity(new SecurityRequirement().requirement("corpId"));
}
}

Cannot invoke method render() on null object in Grail while email sending

I am using mail:1.0.1 plugin for mail sending
but while sending mail its gives me an error..
Source :-
def serviceMethod(EmailModel mailObj) {
PageRenderer groovyPageRenderer;
try{
sendMail {
to "abc#gmail.com"
subject mailObj.subject;
html groovyPageRenderer.render(template:"myMailTemplate", model: [mailObj: mailObj])
}
} catch (Throwable th) {
th.printStackTrace();
}
}
If you want to send the gsp page as email body then you can send it like:
def mailService
def serviceMethod(EmailModel mailObj) {
...
mailService.sendMail {
to email
subject "subject"
body(view: "/_template", model: [mailObj: mailObj])
}
...
}
EDIT...................................................................................
Just inject PageRenderer groovyPageRenderer globally, like
import grails.gsp.PageRenderer
class TestService {
PageRenderer groovyPageRenderer
def getText() {
String s = groovyPageRenderer.render(template: "../first/temp", model: [name: 'user1690588'])
println "Content = ${s}"
}
}
I think you are calling Service Class(.groovy) method from java class.
by using object of EmailService class.
So you cant get Object of PageRenderer class.
for this
Create SpringsUtil Class in src/java and define constant object of EmailSerevice. like this
public class SpringsUtil {
public static ApplicationContext getCtx() {
return getApplicationContext();
}
public static ApplicationContext getApplicationContext() {
return (ApplicationContext) ServletContextHolder.getServletContext().getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT);
}
#SuppressWarnings("unchecked")
public static <T> T getBean(String beanName) {
return (T) getApplicationContext().getBean(beanName);
}
public static final String EMAIL_SERVICE = "emailService";
// public static final String INVENTORY_REORDER_SERVICE = "InventoryReorderService";
}
create object of Service class and call method
EmailService emailService = SpringsUtil.getBean(SpringsUtil.EMAIL_SERVICE);

MonoDroid & RestSharp, MethodMissingException

I'm trying to use RestSharp with MonoDroid and I'm running into some problems. A MethodMissingException is thrown with the message "Default constructor not found for type EmPubLite.Android.Tweet[]." I can only see the exception when I inspect the Task in the VS debugger, it doesn't show up in LogCat. I know that the exception is related to the JSON deserialization in RestSharp.
The linker is set to 'None' in MonoDroid options, and I also tried adding the [Preserve] attribute to my DTOs.
Beyond getting this to work, why doesn't this crash and show up in LogCat? I'd like any Tasks that fail with exceptions to rethrow the exception when I access the result.
[Activity(Label = "EmPubLite", MainLauncher = true, Icon = "#drawable/icon")]
public class EmPubLiteActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.EmPubLight);
var client = new TwitterClient();
client.Search("bielema").ContinueWith(tweets =>
{
Debug.WriteLine("back");
Debug.WriteLine(tweets.Result[0].Text); // Exception not showing up in LogCat
});
}
}
public class TwitterClient
{
private RestClient client = new RestClient();
public Task<Tweet[]> Search(string query)
{
var request = new RestRequest("http://search.twitter.com/search.json?rpp=5&include_entities=true&result_type=mixed&q={q}", Method.GET);
request.AddUrlSegment("q", query);
var taskCompletionSource = new TaskCompletionSource<Tweet[]>();
client.ExecuteAsync<SearchResult>(request, response =>
{
if (response.ErrorException != null) taskCompletionSource.TrySetException(response.ErrorException);
else taskCompletionSource.TrySetResult(response.Data.Results);
// taskCompletionSource.TrySetResult(response.Data.Results);
});
return taskCompletionSource.Task;
}
}
public class SearchResult
{
public Tweet[] Results { get; set; }
}
public class Tweet
{
public string Text { get; set; }
}
I fixed this by using the ServiceStack JSON parser instead of the default RestSharp JSON parser.

Resources