ServiceStack request filter Attribute set a custom object - servicestack

I am trying to write a Custom RequestFilterAttribute that would run on every service to check if the request has a a valid token. I want to return or set an object once the CanExecute method is called and forward it to the service method for further processing. Is there a way to do that in ServiceStack .

ServiceStack Request Filters lets you short-circuit a request so it does no further processing, to let a request go through you'd just ignore the request. One way to do this for specific Requests is to have them share a common interface which you can verify in your Request Filter, e.g:
public interface IValidateToken
{
string Token { get; }
}
public class MyRequest : IValidateToken
{
public string Token { get; set; }
}
Then in a Global Request Filter you can verify if the token is valid, otherwise return an error and short-circuit the request with something like:
GlobalRequestFilters.Add((httpReq, httpRes, dto) => {
var tokenRequest = dto as IValidateToken;
if (tokenRequest != null && !MyValidateToken(tokenRequest.Token))
{
httpRes.StatusCode = (int) HttpStatusCode.Forbidden;
httpRes.StatusDescription = "Token is invalid";
httpRes.EndRequest();
}
});
If the Request Token is valid the request gets processed as normal.

Related

Unable to get from ServiceStack API using JsonServiceClient

I am trying to get all equipment types from my API using the following code.
client = new JsonServiceClient(environment.apiEndpoint);
var equipmentTypes = new GetEquipmentTypes();
var response = this.client.get(equipmentTypes);
I can see that it is in the network tab. The data is being transferred.
public class GetEquipmentTypeResponse
{
public IEnumerable<EquipmentType> Results { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
Is the return DTO from the API.
[Route("/api/EquipmentTypes", "GET")]
public class GetEquipmentTypes : IReturn<GetEquipmentTypeResponse>
{
}
Is the ServiceInterface used.
IEnumerable<EquipmentType> response = db.Select<EquipmentType>(x=>x.Name == request.Name);
return new GetEquipmentTypeResponse { Results = response,
ResponseStatus = new ResponseStatus { }};
Is what the API returns.
The API is written in asp.net. The client side is angular 6 (typescript).
I have attached two images, which is the request and the response given.
This is the request which is sent to the API.
This is what the API responds.
This is what I get from var response. (console.log(response))
The screenshot shows that the response is being returned fine, the Promise result is just not being awaited, try:
var response = await this.client.get(equipmentTypes);

How to validate a REST Assured request across multiple java methods?

I am writing REST Assured tests using Cucumber.
Here is my feature file:
Given I want to GET a client
When I request a client
Then the status code is "theStatusCode"
And the id returned is "expectedClientId"
The below method is called within the Step Definition of the "And" in my feature file
public void validateResponseBody(String expectedClientId){
RestAssured.given()
.when()
.get(completeURL)
.then()
.statusCode(Integer.parseInt(theStatusCode))
.and()
.body("Client.Id", equalTo(expectedClientId));
}
This method currently works, but how do I split the validation?
I.e. how can I break this up to validate the Status Code in one method, & validate the Client Id in another method without having to send the request twice?
Save response to variable:
public void validate() {
ValidatableResponse response = RestAssured.given()
.when()
.get(completeURL)
.then();
validateStatusCode(response, statusCode);
validateResponseBody(response, expectedClientId);
}
public void validateStatusCode(ValidatableResponse response, String statusCode) {
response
.statusCode(Integer.parseInt(theStatusCode));
}
public void validateResponseBody(ValidatableResponse response, String expectedClientId) {
response
.body("Client.Id", equalTo(expectedClientId));
}
I suggest to make changes in Feature File.
New File should be given below. You don't need a when statement here.
Scenario: I want to GET a client
Given I request a client
Then the status code is "theStatusCode"
And the id returned is "expectedClientId"
#Given("I request a client$")
public void validate()
{
ValidatableResponse validatableResponse = RestAssured.given()
.when()
.get(completeURL)
.then();
}
#Then("the status code is \"([^\"]*)\"$")
public void validateStatusCode(String statusCode)
{
validatableResponse.assertThat().statusCode(Integer.parseInt(theStatusCode));
}
#And("the id returned is \"([^\"]*)\"$")
public void validateClientId(String expectedClientId)
{
validatableResponse.assertThat().body("Client.Id", equalTo(expectedClientId));
}

Content-Type must be 'application/json-patch+json' JsonServiceClient ServiceStack

I'm trying to perform a patch with a JsonServiceClient to a service stack api as follows:
var patchRequest = new JsonPatchRequest
{
new JsonPatchElement
{
op = "replace",
path = "/firstName",
value = "Test"
}
};
_jsonClient.Patch<object>($"/testurl/{id}", patchRequest);
But I'm getting the following error:
Content-Type must be 'application/json-patch+json'
The error is clear. Is there a way to change the content type before perform the request for the JsonServiceClient?
This is the request POCO in the ServiceStack api:
[Api("Partial update .")]
[Route("/testurl/{Id}”, "PATCH")]
public class PartialTest : IReturn<PartialTestRequestResponse>, IJsonPatchDocumentRequest,
IRequiresRequestStream
{
[ApiMember(Name = “Id”, ParameterType = "path", DataType = "string", IsRequired = true)]
public string Id { get; set; }
public Stream RequestStream { get; set; }
}
public class PartialTestRequestResponse : IHasResponseStatus
{
public ResponseStatus ResponseStatus { get; set; }
}
Service implementation:
public object Patch(PartialTest request)
{
var dbTestRecord = Repo.GetDbTestRecord(request.Id);
if (dbTestRecord == null) throw HttpError.NotFound("Record not found.");
var patch =
(JsonPatchDocument<TestRecordPoco>)
JsonConvert.DeserializeObject(Request.GetRawBody(), typeof(JsonPatchDocument<TestRecordPoco>));
if (patch == null)
throw new HttpError(HttpStatusCode.BadRequest, "Body is not a valid JSON Patch Document.");
patch.ApplyTo(dbTestRecord);
Repo.UpdateDbTestRecord(dbTestRecord);
return new PartialTestResponse();
}
I'm using Marvin.JsonPatch V 1.0.0 library.
It's still not clear where the Exception is coming from as it's not an Error within ServiceStack. If you've registered a Custom Format or Filter that throws this error please include its impl (or a link to it) as well as the full StackTrace which will identify the source of the error.
But you should never call Patch<object> as an object return type doesn't specify what Response Type to deserialize into. Since you have an IReturn<T> marker you can just send the Request DTO:
_jsonClient.Patch(new PartialTest { ... });
Which will try to deserialize the Response in the IReturn<PartialTestRequestResponse> Response DTO. But as your Request DTO implements IRequiresRequestStream it's saying you're expecting unknown bytes that doesn't conform to a normal Request DTO, in which case you likely want to use a raw HTTP Client like HTTP Utils, e.g:
var bytes = request.Url.SendBytesToUrl(
method: HttpMethods.Path,
requestBody: jsonPatchBytes,
contentType: "application/json-patch+json",
accept: MimeTypes.Json);
You could modify the ContentType of a JSON Client using a request filter, e.g:
_jsonClient.RequestFilter = req =>
req.ContentType = "application/json-patch+json";
But it's more appropriate to use a low-level HTTP Client like HTTP Utils for non-JSON Service Requests like this.

GetRawBody() is returning empty for REST requests

I am trying to write the Raw data of my ServiceStack webservice using servicerunner. This is working for SOAP requests but for the REST request GetRawBody() is returning empty.
public override void BeforeEachRequest(IRequest requestContext, T request)
{
Logger.Write(requestContext.GetRawBody());
}
By default web servers only provide a forward-only Request Stream which you can tell ServiceStack to skip deserialization so you can read from the Request Stream by implementing IRequiresRequestStream on your Request DTO:
public class MyRequest : IRequiresRequestStream
{
Stream RequestStream { get; set; }
}
Which will inject the Request Stream instead of deserializing the Request DTO, e.g:
public class object Any(MyRequest request)
{
var requestBody = request.RequestStream.ReadFully().FromUtf8Bytes();
}
Otherwise if you want ServiceStack to deserialize the Request and you want to re-read from the Request Body later yourself you need to tell ServiceStack to buffer the Request using a pre-request filter:
appHost.PreRequestFilters.Add((httpReq, httpRes) => {
httpReq.UseBufferedStream = true;
});

How would I change a ServiceStack response DTO

I'm working on an API where I'd like to be able to customize the response structure based on a parameter from the client. Response filters seem like a good place to do this in order to avoid doing so in each service or action. The problem is that while I have access to the response DTO returned by the action, and could change its properties, I can't find how or where to replace the object entirely.
Naively replacing the object in the response filter did not work, but this help illustrate what I'm trying to do:
public class ChangeResponseAttribute : ResponseFilterAttribute
{
public override void Execute(IHttpRequest req, IHttpResponse res, object responseDto)
{
var overrideText = req.QueryString["override"];
if (!String.IsNullOrEmpty(overrideText))
responseDto = new { Message = overrideText };
}
}
[ChangeResponse]
public class TodosService : Service
{
public object Get(Todos request)
{
return new object[0];
}
}
It looks like another option would be to write the custom response directly & end the request, but that would bypass any other processing left to do by ServiceStack.
Is there a better place to do this than a response filter? Or do I need to bite the bullet and return the optimal DTO in each action?
You can't change the Response DTO in a filter, but yes one option is to write the response in the filter itself (see this answer for an example of how to do this).
The other option is to use a ServiceRunner and override the OnAfterExecute() custom hook which does let you modify the response returned, e.g:
public class MyServiceRunner<T> : ServiceRunner<T>
{
public override object OnAfterExecute(
IRequestContext requestContext, object response)
{
// Called just after any Action is executed
var overrideText = req.Get<IHttpRequest>().QueryString["override"];
return !string.IsNullOrEmpty(overrideText)
? new { Message = overrideText } : null;
}
}
To get ServiceStack to use it you need to override the CreateServiceRunner method in your AppHost, e.g:
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(
ActionContext actionContext)
{
return new MyServiceRunner<TRequest>(this, actionContext);
}

Resources