I'm writing a backend using ServiceStack. our main front end client is an Angular 2 application using TypeScript. To that end, we are using the DTOs that are generated by the services when hitting /types/typescript and /types/typescript.d. This all works fine and good using the JsonServiceClient... but it seems that the response status code is somehow wrapped up in the call and not returned as it as when using a standard XHR call.
Finding the AddResponseStatus configuration item, I changed the service configuration to add this on any DTO that didn't already have the property (which mine didn't):
var ntf = new NativeTypesFeature();
ntf.MetadataTypesConfig.AddResponseStatus = true;
Plugins.Add(ntf);
After refreshing the TypeScript reference, I can see that all DTO types returned now have a ResponseStatus property on them.
export class QueryReportResponse
{
Data: string;
ResponseStatus: string;
}
Here is a scrubbed return (removed the 'Data' portion) showing the property exists on the object:
<QueryReportResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/blah.blah.ServiceModel.Messages">
<Data>
blah blah data here
</Data>
<ResponseStatus i:nil="true"/>
</QueryReportResponse>
Now, I assumed (wrongly so) that by doing this, some sort of status would be set 'automatically'. I'm obviously not right here, as this property is not set. My front end guy is asking to be able to see the status on all returned calls, like he was able to before when using straight XHR prior to using the JsonServiceClient, as now he cannot see the return status.
What is the intent of this field? I cannot set it manually, as it's added by ServiceStack dynamically at runtime. I can only assume that I would have to create my own base class return DTO of sorts and set that on the way back to the caller... can someone help me understand the purpose of this field? Thanks.
ServiceStack's Add TypeScript Reference is typically used with the TypeScript servicestack-client. The ResponseStatus is used in ServiceStack's Error Handling which is used to capture structured Error Information. It's not populated for successful responses and it's distinct from the HTTP Response Status code although if throwing a HTTP Error the ResponseStatus.ErrorCode will typically contain the HttpStatusCode enum string.
Adding ResponseStatus on DTOs
Adding the ResponseStatus on DTOs, e.g:
ntf.MetadataTypesConfig.AddResponseStatus = true;
Just adds the ResponseStatus on generated DTOs where they didn't previously exist. It doesn't have any effect on Response DTOs which already includes the ResponseStatus property, e.g:
public class MyResponse
{
public ResponseStatus ResponseStatus { get; set; }
}
Accessing HTTP Status Responses
Developers shouldn't care what the HTTP Status code is for successful responses (which is almost always 200 OK). ServiceStack's TypeScript JsonServiceClient will just return the Typed Response DTO for successful responses, e.g:
var response = await client.post(request)
They should only be interested for handling error responses, however it's expected to use the ResponseStatus.ErrorCode to determine the type of Error and apply application error handling logic, e.g:
try {
var response = await client.post(request)
} catch (e) {
console.log(e.responseStatus.errorCode);
}
If they really want the HTTP Status they can get it using a response filter, e.g:
var status = null;
try {
client.responseFilter = res => status = res.status;
var response = await client.post(request)
} catch (e) {
console.log(status, e.responseStatus.errorCode);
}
Related
Probably everyone was facing the issue when Postman documentation will be barely up-to-date with the code currently running in dev or production.
Almost every time the source of that problem is "a little change" or adding a new column into the database.
So I would like the code to be self-documented, starting from the validator.
There is the wrap-implementation over the JOI validator
class Validator {
_schema = {};
static TYPES = Joi;
setRule(field, rule){
this._schema[field] = rule;
}
validate(data){
let schema = Joi.object(this._schema);
try {
Joi.assert(data, schema, {abortEarly: false});
}
catch(error){
const message = error.details.map(detail => detail.message);
throw new ValidationError(message);
}
}
}
The controller uses this wrap just like that
const validator = new Validator();
validator.setRule('sts', Validator.TYPES.string());
validator.validate(body);
Every time the crucial code change happens, it usually affects the incoming body validation.
So the idea behind self-documentation is why not to use validator class as a source of the API documentation? We could get almost every piece of information about the endpoint using router + validator.
But how can you collect the data about that for every endpoint (especially, controller).
We should somehow get access to every instance of the Validator class inside each controller?
Or shall we just read the source file to get an information about the rules?
There are several implementations of Swagger-like docs, but they are all based on decorators code style, from which we are trying to get rid of.
Im using servicestack Core with kestrel. I made a CatchAllHandlers delegate with the following code.
var requestType = typeof(NotFoundPage);
var restPath = new RestPath(requestType, pathInfo);
return new RestHandler { RestPath = restPath, RequestName = restPath.RequestType.GetOperationName(), ResponseContentType = contentType };
But the problem is that my ServicestackApi now is no longer reachable, url: /json/reply/GetApiCall goes to the 404 not found page.
Is there a way to solve this? can i check if its an api call or can i go later in the pipeline to handle the request?
update
I found that if i remove CatchAllHandler and just add the next middleware this middleware is called:
app.Use((context, next) =>
{
context.Response.Body.Write("yaayaya");
return Task.CompletedTask;
});
But this is not what i want, i want to stay inside the servicestack request.
update 2
Looking at the source-code i find HttpHandlerFactory has a property NotFoundHttpHandler Which is filled from the AppHost.
CustomErrorHttpHandlers.Add(HttpStatusCode.NotFound, new PageNotFoundHandler());
The only downside is that i can't provide any request specific information to this Urlhandler, such as the url itself:
public class PageNotFoundHandler : RestHandler
{
public PageNotFoundHandler()
{
var restPath = new RestPath(typeof(Error404), "/Url/For?");
}
}
Trying to make this work but i'm getting stuck on that my RestHandler has different amount of components than the url since this PageNotFoundHandler is made before the RestHandler.
But Basically what im looking for is to Handle a different service/InputDto
I've tried RequestConverters but this code is not reached when CatchAllHandlers doesn't return an Handler. so im stuck in this space in the middle. Anyway i could make all the left over routes, route to a single Dto?
.NET Core's new pipeline programming model expects you to call the next middleware if it wasn't already handled by any of the previously registered middleware which is how .NET Core lets you combine multiple different middlewares into the same App.
Handling Not Found Requests with the last Middleware
The last middleware that's registered will be able to handle any unhandled requests so for instance if you wanted to return a static image for unhandled requests you could register middleware after ServiceStack, e.g:
app.UseServiceStack(new AppHost());
app.Use(new StaticFileHandler("wwwroot/img/404.png"));
Or if you wanted to return a custom 404 page instead:
app.Use(new RazorHandler("/404"));
Which will render the /wwwroot/404.cshtml Razor View with ServiceStack's MVC Razor Views.
This would be the preferred way to handle Not Found requests in .NET Core in which you will be able to register additional middleware after ServiceStack to handle non-ServiceStack requests.
Calling a ServiceStack Service for unhandled requests
If you wanted to call a ServiceStack Service for any unhandled requests you can use a Fallback Route which matches on any request, e.g:
[FallbackRoute("/{Path*}")]
public class Error404
{
public string Path { get; set; }
}
public class UnhandledRequestService : Service
{
public object Any(Error404 request) => ...;
}
Hopefully you guys can help me with this! I have a problem where I need to send a constant response code no matter what the request contains. If the request has bad JSON etc. The response I need to send is a 204 (No Content)
Here's my code where I try to send back a no content header.
public Result response(){
RequestBody body = request().body();
System.out.println(body.asJson());
return noContent();
}
Now if I try and send a request containing JSON like below. It returns a 400 (Bad request). I want to send a 204 no matter what. Please let me know what you guys come up with.
JSON POST
{
"mike":"mike
}
Thanks
Edit:
Sorry I replaced one of these lines of code and forgot to update this. Above I only return 204's, but if my client sends me bad JSON then I still return a 400.
You need to modify the global settings for play.
Create a class that extends Global Settings and override whichever method you want.
public class Global extends GlobalSettings {
#Override
public Promise<Result> onBadRequest(RequestHeader arg0, String arg1) {
super.onBadRequest(arg0, arg1);
return F.Promise.promise(()->{return play.mvc.Results.noContent();});
}
}
For more information : https://www.playframework.com/documentation/2.4.x/JavaGlobal
To return 204, you can use noContent method
For that replace ok() by noContent()
Try this,
#BodyParser.Of(BodyParser.Json.class)
public static Result response() {
JsonNode json = request().body().asJson();
if(json == null){
return noContent();
}else{
// Get json content from request and process rest..
}
return ok("");
}
By using above approach, a 204 HTTP response will be automatically returned for non JSON requests.
While in the ResponseFilters is there anyway to get the status code (and description) which is going back to the client?
Long explanation:
I'm looking into adding a response header while I'm in a response filter. The issue is that in our API we set on some NotFound & BadRequest returns a message for the user in the status description;
return HttpError.NotFound(string.Format("Not found with TicketCodeId {0}",
request.TicketCodeId))
This works great in android and .net clients of all sorts.
But some clients (I'm looking at you iphone) don't get the status description. The idea is to see in the responsefilter that the status code is set to 400 range and it has a special message, then add a header and copy the status message description into it.
Problem is ResponseFilter has access to IHttpResponse, and that object has only a setter to the statuscode (so no way for me to determine if I need to add the header).
I want to solve it in this generic way to avoid having to remember (and go back over all service implementations) everywhere a 400 status code is set to add the same description to a header. It would be nice if this is done in a single place, the ResponseFilter.
ResponseFilter documentation
Since we are returning all responses with BadRequest and NotFound where we use a message in the status description as either an HttpError or HttpResult (which both are of type IHttpResult) I can do the following to create the desired extra header:
// Add Filter: If result is of type IHttpResult then check if the statuscode
// is 400 or higher and the statusdescription is set.
this.ResponseFilters.Add((req, res, dto) =>
{
if (dto == null) return;
var httpResult = dto as IHttpResult;
if (dto is IHttpResult)
{
// If statuscode is 400 then add a Header with the error message;
// this since not all clients can read the statusdescription
if ((int)httpResult.StatusCode >= 400)
AddPmErrorMessageHeader(res, httpResult.StatusDescription);
}
});
The AddPmErrorMessageHeader method will do some extra validation and use the res object to add the header:
res.AddHeader("PmErrorMessage", statusDescription);
I did some testing with the res.OriginalResponse but that somehow always has the StatusCode set to 200, even when just before setting the 4** status code.
have created REST service using servicestack and in post request I have return object in following way
return new HttpResult(request)
{
StatusCode = HttpStatusCode.Created,
};
request: object which i have posted in database
When i check it in fiddler it render whole HTML Page of servicestack in response body, instead of that i would like to return Status code only, so please tell me how can i do?
Thanks
There was a bug in versions before < v3.05 that did not respect the HttpResult ContentType in some scenarios, it should be fixed now with the latest version of ServiceStack on NuGet or available from:
https://github.com/ServiceStack/ServiceStack/downloads
Prior to this you can still force the desired ContentType by changing the Accept:application/json Request Header on HttpClient or by appending ?format=json on the querystring of your url.
So now if you don't want to have any DTO serialized, you don't add it to the HttpResult:
return new HttpResult() { StatusCode = HttpStatusCode.Created };
Note you still might get an empty Html response back if calling this service in the browser (or any Rest Client that Accepts:text/html). You can force a ContentType that won't output any response if it has empty payload (e.g JSON/JSV) by specifying it in the result as well, e.g;
return new HttpResult() {
StatusCode = HttpStatusCode.Created,
ContentType = ContentType.Json
};