Accept header precedence with spring-data-rest - spring-data-rest

I am trying spring-data-rest with mithril.js. However, I keep getting xml response from the repository instead of json.
I have this repository:
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends JpaRepository<Person, Long> {
And request with this:
var users = m.request({method: "GET", url: "/api/people/"});
However, I just got a list of string in xml response.
I tried to check the source as below, though I may mislook and point out the wrong source:
Found that mithril set the accept header as
xhr.setRequestHeader("Accept", "application/json, text/*")
mithril source: line 1079
However, it sounds spring-data-rest handle the request with
#ResponseBody
#SuppressWarnings({ "unchecked" })
#RequestMapping(value = BASE_MAPPING, method = RequestMethod.GET, produces = {
"application/x-spring-data-compact+json", "text/uri-list" })
public Resources<?> getCollectionResourceCompact(RootResourceInformation repoRequest, DefaultedPageable pageable,
spring-data-rest source: line 171-173
instead of
#ResponseBody
#RequestMapping(value = BASE_MAPPING, method = RequestMethod.GET)
public Resources<?> getCollectionResource(final RootResourceInformation resourceInformation,
on spring-data-rest source: line 210-213
Is anything wrong on my ajax request?

Use curl to create the request and get that working the way you think it should. After that works, tackle the mithril part.

Related

Does StringContentProvider set Content-Type header in HTTP request?

I am trying to use Firebase Cloud Messaging by Google with the help of Jetty HTTP client:
public static final String FCM_URL = "https://fcm.googleapis.com/fcm/send";
public static final String FCM_KEY = "key=AAAA....";
private final HttpClient mHttpClient = new HttpClient();
private final CompleteListener mFcmListener = new CompleteListener() {
#Override
public void onComplete(Result result) {
if (result.isFailed()) {
// TODO delete FCM token in database for certain responses
}
}
};
mHttpClient.start();
mHttpClient.POST(FCM_URL)
.header(HttpHeader.AUTHORIZATION, FCM_KEY)
.content(new StringContentProvider(notificationStr), "application/json")
.send(mFcmListener);
My question is very simple, but I couldn't find the answer myself yet by looking at the StringContentProvider and its base classes -
If I need to set the request HTTP header for FCM:
Content-Type: application/json
then do I have to add the line:
.header(HttpHeader.CONTENT_TYPE, "application/json")
or will that class already do it for me?
A couple of points:
Yes, if you don't set content type header explicitly, it would be auto set based on the selected Content Provider.
By default, the StringContentProvider sets Content-Type to text/plain. To override, you need to use another constructor -
new StringContentProvider("application/json", content, StandardCharsets.UTF_8);
Request #setContent method auto sets Content-Type header to the provided value. Hence, you need not make any change to the code.

Response pipeline

I came across a difficulty while was working with Asp.net core 1.0 RTM. For example in case bellow we will see output result as "-Message_1--Message_5-":
public class MessageMiddleware
{
private readonly RequestDelegate _next;
private readonly IApplicationBuilder _app;
public MessageMiddleware(RequestDelegate next, IApplicationBuilder app)
{
_next = next;
_app = app;
}
public async Task Invoke(HttpContext context)
{
var started1 = context.Response.HasStarted;//false
await context.Response.WriteAsync("-Message_1-");
var test = true; // will hit this line
var started2 = context.Response.HasStarted;//true
await context.Response.WriteAsync("-Message_5-");
await _next.Invoke(context);
}
}
But in this case (header "Content-Type" was added) the result will be only "-Message_1-" and execution is really stopped:
public class MessageMiddleware
{
private readonly RequestDelegate _next;
private readonly IApplicationBuilder _app;
public MessageMiddleware(RequestDelegate next, IApplicationBuilder app)
{
_next = next;
_app = app;
}
public async Task Invoke(HttpContext context)
{
var started1 = context.Response.HasStarted;//false
await context.Response.WriteAsync("-Message_1-");
var started2 = context.Response.HasStarted;//true
context.Response.ContentType = "text/html";
var test = true; // will NOT hit this line
var started3 = context.Response.HasStarted;//will NOT hit this line
await context.Response.WriteAsync("-Message_5-"); //will NOT hit this line
await _next.Invoke(context);
}
}
I found only this remark in official documentation:
Avoid modifying HttpResponse after invoking next, one of the next components in the pipeline may have written to the response, causing it to be sent to the client.
and this question at SO: Why can't the HttpResponse be changed after 'next' call?
But it's not enough to understand interaction with props of HttpContext.Response during middleware pipeline and how this interection affects on final result - headers and body content of HttpResponse.
Could somebody explain general behaviour of processing response by ASP.NET core? For example, when response headers are send to client and how setting HttpContext.Response properties(headers, body content) affects on this?
When pipeline inside(outside) middliware is terminated?
Thank you!
As a general rule, when the client makes a request to the server, it gets back a response. That response contains headers and a body. The headers contain many pieces of information about the response like the content type, encoding/compression used, cookies, etc. Here is an example of the headers sent back by the live.asp.net site as seen in the chrome developer tools:
The other part of the response is the body. It often contains html or json. Here is a screenshot of the body for the same response:
The easiest way to think about it is to think of these two being sent together to the client, first the headers then the body. So as a developer, your only opportunity to set any value on the response object that affects the headers is up to the point at which you start sending the body. One you begin sending the body of the response you can no longer change the headers because they are sent as the first part of the response just before the body begins sending.
That's why #tseng said "Don't set headers after you have written something to the response stream".
If a developer isn't familiar with http headers they might not realize that context.Response.ContentType = "text/html" is changing a header, but under the hood, that's exactly what it is doing. Likewise, setting a cookie changes a response header under the hood. In general, if you are changing some property of the response object you should ask yourself "will this change an http header?" and if the answer is "yes" then you need to do it before you make a call to Response.WriteAsync.

How can i get html headers with phpunit using Selenium2?

public function testheaders()
{
$url=$this->url('http://www.example.com/index.php');
$kur = get_headers($url);
var_dump($kur);
}
I got the error : get_headers(): Filename cannot be empty.
My class extends PHPUnit_Extensions_Selenium2TestCase like my all my other tests.
get_headers() is a PHP function that will give you the headers return by an HTTP request to a specified url. The parameter you need to give is a string, but $this->url() return an PHPUnit_Selenium-object.
If you want the headers of that known URL, why not do directly?
$kur = get_headers('http://www.example.com/index.php');

Request and Response Headers Override using Restler

I am new to restler and trying to do the following things, can't seem to get hold of it
I have this class and method exposed via Restler
class Account {
protected $Api_Version = array('version' => "1.0.2.1234", 'href' => "/");
// Returns the version of the service
// Content-Type: application/vnd.cust.version+json
function version() {
return json_encode($this->version);
}
// Accepts only Content Type: application/vnd.cust.account+json
function postCreate() {
}
}
1) I want to return my own Content-Type to client like in the 'version' method instead of default application/json. In my case its 'application/vnd.cust.version+json'
2) Method postCreate should only accept the request if the Contet-Type is set to 'application/vnd.cust.account+json'. How to check if that header is set in the request.
3) Also in the restler API Explorer, for methond name, how can I show only the method name instead of the 'version.json'. I want to show just 'version' like the method name
Thank you for your help.
Narsi
1) maybe Write your own format? Take a Look at
http://restler3.luracast.com/examples/_003_multiformat/readme.html
2) you could check the headers and throw Exception on wrong one.
Take a Look at this link
http://stackoverflow.com/questions/541430/how-do-i-read-any-request-header-in-php
3) have you tried to and the following line to your Index.php?
Resources::$useFormatAsExtension = false
Hope takes you further on :)
CU
Inge

HTTPService not properly JSON-encoding nested objects on send()

i am creating an object like this:
var myObj:Object = new Object();
myObj["someProperty"] = {
anotherProperty: "someValue",
whateverProperty: "anotherValue"
}
now i want to send it to a web server (rails):
var service:HTTPService = new HTTPService();
service.url = "http://server.com/some/path/entry.json";
service.method = URLRequestMethod.POST;
service.send( myObj );
the problem is that the server receives the json like this:
{"someProperty"=>"[object Object]"}
is this a problem with HTTPService? should i use the good old loader/urlrequest and serialize myself? by the way, serializing and then passing the string doesn't work, webserver receives empty request as GET.
but i kinda want to use the httpservice class though...
You can use a SerializationFilter with your HTTPService to correctly serialize the data you pass as an object to HTTPService.send().
The way in which this works is to create a custom SerializationFilter to perform the specific action required. In your case, you want to convert the outgoing body Object to a JSON format String. To do this you should override the serializeBody method:
package
{
import mx.rpc.http.AbstractOperation;
import mx.rpc.http.SerializationFilter;
import com.adobe.serialization.json.JSON;
public class JSONSerializationFilter extends SerializationFilter
{
override public function serializeBody(operation:AbstractOperation, obj:Object):Object
{
return JSON.encode(obj);
}
}
}
You can assign an instance of this filter to your HTTPService before calling send():
var service:HTTPService = new HTTPService();
service.url = "http://server.com/some/path/entry.json";
service.method = URLRequestMethod.POST;
//add the serialization filter
service.serializationFilter = new JSONSerializationFilter();
service.send( myObj );
Once assigned, this filter will be invoked for all the operations this HTTPService instance performs. You can also add more override methods to your custom filter to handle the incoming response.
I highly recommend using Mike Chamber's JSON serialization library for encoding / decoding (serializing) data in JSON.
Basically, you need to convert your object into a JSON representation. The JSONEncoder class is useful for this.
There's a useful (old but still very relevant for using HTTPService + JSON) tutorial that goes through it, but essentially you should call JSON.encode() on what your "someProperty" value is.
i.e.:
var dataString:String = JSON.encode(dataValue);
dataString = escape(dataString);
myObj["someProperty"] = dataString;