Trying to override the headers of Laminas XML-RPC server response. The header Content-Type should be application/xml instead of the default text/html. Having read the docs it isn't clear what to do, it states:
Similar to request objects, Laminas\XmlRpc\Server can return custom response objects; by default, a Laminas\XmlRpc\Response\Http object is returned, which sends an appropriate Content-Type HTTP header for use with XML-RPC. Possible uses of a custom object would be to log responses, or to send responses back to STDOUT.
To use a custom response class, use Laminas\XmlRpc\Server::setResponseClass() prior to calling handle().
There is a example usage of setResponseClass() but not what the class should look like. The only thing that is clear from looking at the source is that it should extend Laminas\XmlRpc\Response and that's it.
What I have tried but isn't working:
use Laminas\XmlRpc\Response as XmlRpcResponse;
/**
* HTTP response
*/
class XmlRpcService extends XmlRpcResponse
{
protected $type = 'application/xml'; // This was just for testing but isn't working either
/**
* Override __toString() to send HTTP Content-Type header
*
* #return string
*/
public function __toString()
{
if (! headers_sent()) {
header('Content-Type: application/xml; charset=' . strtolower($this->getEncoding()));
}
return parent::__toString();
}
}
$server = new \Laminas\XmlRpc\Server();
$server->setClass( 'SomeClass', 'namespace' );
$server->setResponseClass( XmlRpcService::class);
return $server->handle();
Hope some one can point me in the right direction of how to override the headers. Related report: https://discourse.laminas.dev/t/how-to-override-the-headers-of-xml-rpc-server-response/1632
As I'm using Laravel I'm able to do the following. This way it isn't required to use a additional class for $server->setResponseClass( XmlRpcService::class);. Apparently Laravel can take the $server->handle(), which on it's own is already a response, and set the required headers.
return response($server->handle(), 200)->header('Content-Type', 'text/xml');
Related
I'm migrating an application from NancyFx to Kestrel in ASP.NET Core 6.
In Nancy, you could specify the Accept value in the URI. For example, these Uris:
http://localhost:5000/my/resource.json
http://localhost:5000/my/resource.protobuf
http://localhost:5000/my/resource.xml
Would be the equivalent of setting the Accepts header to application/json, application/protobuf or application/xml respectively.
Does this exist in Kestrel? I remember finding one example, long ago, of regex-ing the route and doing it somewhat manually. But
I can't find that post again, and
If I have to do that, I'm not sure I want to :)
Is there a way to configure this behavior in ASP.NET Core 6?
The object returned from my handler in the controller is already capable of being serialized to json/xml/whatever. I just need to check the URI to set the content-type of the response so the correct formatter will be invoked.
At the moment, I have a client that will speak to both Nancy and Kestrel and it was written to use the URI to get the type. I'm fine to rewrite/update the client so it will use the Accept header. But getting the URI method to work will make the initial integration easier and a refactor to use the headers can come next.
I created a very simple middleware that reads the accept value from the query string and sets the Accept header to the request:
public class AcceptHeaderFromQueryString
{
private readonly RequestDelegate _next;
public AcceptHeaderFromQueryString(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var accept = context.Request.Query["accept"];
if (!string.IsNullOrEmpty(accept))
{
context.Request.Headers.Accept = accept;
}
await _next(context);
}
}
Register the middleware:
app.UseMiddleware<AcceptHeaderFromQueryString>();
I added [Produces(MediaTypeNames.Application.Json, MediaTypeNames.Application.Xml)] attribute to my api controller action (this step is not required):
[HttpGet]
[Produces(MediaTypeNames.Application.Json, MediaTypeNames.Application.Xml)]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
Finally I added support for xml serialization in Program.cs:
builder.Services.AddControllers()
.AddXmlDataContractSerializerFormatters();
Then I tried these urls and they both gave appropriate response:
https://localhost:7258/weatherforecast?accept=application/json
https://localhost:7258/weatherforecast?accept=application/xml
You possibly want the [Consumes] attribute. This allows you to specify a controller action that only gets called from a route of the specified content type.
Obviously this is not using the Accepts header but the content type of the request.
I'd like to migrate a JAX-RS-REST-Restservice (running under Tomcat) to Quarkus.
I could solve most of my problems along the way but I still have a problem with one method.
In this function I do a OTA-download (firmware for a device). I set some headers and the MediaType and the content length.
In the original service my code looked as follows:
public HomeAutomationService
{
...
#Context
private HttpServletRequest request;
...
#GET
#Produces(MediaType.APPLICATION_OCTET_STREAM)
#Path("/v1/DownloadFirmware")
public Response getFirmware()
{
...
response.setHeader("X-OTA-SIGNATURE", signatureString);
response.setContentLength((int) file.length());
response.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM).build();
}
}
Unfortunately I can't find anything like a HttpServletResponse in Quarkus.
So I now use a ResponseBuilder to create a Response, where I can add headers as needed:
ResponseBuilder responseBuilder;
However, I am not sure how to instantiate the ResponseBuilder. There is a method to set headers for the ResponseBuilder, but I did not find anything on how to the content length and the content type.
I am not sure if I have to set the content-type since I already use a #Produces-annotation - but what about the content length? Is it set automatically? If no (that's what I guess) how can I set it correctly?
Thanks for reading and answering,
Rudi
You don't need to use #Produces in this case and your return should be something like the code below:
return Response.ok(yourFileBytes[])
.type(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_LENGTH, <yourFileLength>)
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; ")
.build();
The code above can be written as:
ResponseBuilder resp = Response.ok(yourFileBytes[]);
resp.type(MediaType.APPLICATION_OCTET_STREAM);
resp.header(HttpHeaders.CONTENT_LENGTH, <yourFileLength>);
resp.header(HttpHeaders.CONTENT_DISPOSITION, "inline; ");
return resp.build();
I am using wiremock to mock http server and I am returning responses from json files (using withBodyFile method).
Now I want to choose and return response json file based on request parameter. For the example below, I want to define one stub so that the body file is chosen based on request parameter.
myMockServer.stubFor(
get(urlEqualTo(myEndPoint+ "?key=key1"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("response_key1.json")
myMockServer.stubFor(
get(urlEqualTo(myEndPoint+ "?key=key2"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("response_key2.json")
myMockServer.stubFor(
get(urlEqualTo(myEndPoint+ "?key=key3"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("response_key3.json")
Any idea how this would be possible? I tried defining transformer but it was not possible to get Stream Source Path from Response object in overridden method so can't use that appraoch. Thanks a lot..
Body File name can't be parameterized in wiremock as of now. I had a similar requirement, I needed to return the file based on the request URL. So I implemented a transformer as below:
public class BodyFileNameResponseTransformer extends ResponseDefinitionTransformer {
public ResponseDefinition transform(Request request, ResponseDefinition rd,
FileSource fileSource, Parameters parameters) {
if (rd.getBodyFileName().startsWith("{{")) {
return new ResponseDefinitionBuilder().**withBodyFile**(request.getUrl().substring(1))
.withStatus(rd.getStatus())
.withHeaders(rd.getHeaders())
.withTransformers(
rd.getTransformers().toArray(new String[rd.getTransformers().size()]))
.build();
}
return rd;
}
public String getName() {
return "BodyFileNameTransformer";
}
}
you can use request.queryParameter(key) instead of request.getUrl() and form any
file path. Create the file path based on your need and set it as bodyFile on returned ResponseDefinition.
Don't forget to start wiremock with --extensions: Extension class names
More details at Extending Wiremock
This is possible by using the inbuilt template helpers provided by Handlebar.
myMockServer.stubFor(
get(urlEqualTo(myEndPoint+ "?key=key3"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("response_{{request.query.key}}.json")
Check for the various models available at http://wiremock.org/docs/response-templating/.
I am trying to run a simple example in Jersey which has a GET method and returns a Custom object.
on calling GET I am getting following error
MessageBodyWriter not found for media type=text/plain
I have looked into few answers on stackoverflow where they are suggesting it to put a default constructor and jackson dependency in pom.xml. I have already done that but no luck. Can some one please suggest what I am doing wrong.
Resource Class
#Path("customdatatyperesource")
public class CustomDataTypeResource {
#GET
public CustomResource1 get(#Context UriInfo ui) {
return new CustomResource1();
}
}
Custom Class
#XmlRootElement
public class CustomResource1 {
#XmlElement
String res;
public CustomResource1() { }
#Override
public String toString(){
return "Custom : "+res;
}
}
pom.xml
Thanks
So I figured out that error is not in the code but in the request sent.
When I send the request with header accept: text/plain
I am getting the error MessageBodyWriter not found for media type=text/plain
The resolution is accept header needs to match with what resource can produce.
In this case our resource is capable of producing XML or JSON
A better and more comprehensive way to write this code would be to put produce annotation on the methods.
#Produces(MediaType.TEXT_XML)
and put correct accept header such as
accept: application/json
I am creating a REST interface and have a resource 'data'. Now I want that an user can specify whether he wants the data as XML or as JSON. Therefore I have created two methods for the same path, one produces application/xml, the other produces application/json. Everything works fine, but how can I specify what should be returned, if an user doesn't set the 'Accept' header field?
My tests have shown that it is not always the same. Yesterday the default was application/xml, today my tests have failed, because as default application/json was returned.
How can I specify a default?
Code Snippet:
#GET
#Path("/rest/data")
#Produces(MediaType.APPLICATION.XML)
public Object getDataAsXML() {
// return data in XML format
}
#GET
#Path("/rest/data")
#Produces(MediaType.APPLICATION_JSON)
public Object getDataAsJSON() {
// return data in JSON format
}
Cheers,
metalhamster
#Path("/myResource")
#Produces("text/plain")// doGetAsPlainText method defaults to the MIME type of the #Produces annotation at the class level.
public class SomeResource {
#GET
public String doGetAsPlainText() {
...
}
#GET
#Produces("text/html")
public String doGetAsHtml() {
...
}
}
The doGetAsPlainText method defaults to the MIME type of the #Produces annotation at the class level. The doGetAsHtml method's #Produces annotation overrides the class-level #Produces setting, and specifies that the method can produce HTML rather than plain text.
#GET
#Produces({"application/xml", "application/json"})
public String doGetAsXmlOrJson() {
...
}
The doGetAsXmlOrJson method will get invoked if either of the media types "application/xml" and "application/json" are acceptable. If both are equally acceptable then the former will be chosen because it occurs first.
#Produce