How to remove hypermedia elements from representations produced by Spring Data REST? - spring

When using Spring Data for my REST API, the responses returned currently include the _links field:
{
"_embedded": {
"users": [
{
"imageUrl": "some_image_url",
"name": "some name",
"id": "57420b2a0d31bb6cef4ee8e9",
"_links": {
"self": {
"href": "http://localhost:8080/users/57420b2a0d31bb6cef4ee8e9"
},
"user": {
"href": "http://localhost:8080/users/57420b2a0d31bb6cef4ee8e9{?projection}",
"templated": true
}
}
},
...
Is there a way to produce output, such that the _links field is hidden? e.g.:
{
"_embedded": {
"users": [
{
"imageUrl": "some_image_url",
"name": "some name",
"id": "57420b2a0d31bb6cef4ee8e9",
},
...
I find that because I am exposing the id field, _links are not really necessary, and mostly just clutter up my responses.

There isn't. Hypermedia is a fundamental trait of REST APIs and Spring Data REST heavily uses it to allow you to build clients that can use the links present in the responses to navigate to related resources.
Of course you can dumb down your clients to not make use of that information but that will lead to a much tighter coupling (as you can't change the URIs on the server side anymore, your clients expects to talk to a dedicated server whereas with hypermedia you can just point it to a different server etc.).
In contrast to a lot of other self-proclaimed REST frameworks out there, one of the key aspects of the framework's design is to respect the fundamental principles in REST and explicitly leverage them. Or at least, don't create incentives to easily break them. This is clearly expressed in the reference documentation and on the project website. Find out more about key design decisions in this presentation on Spring Data REST, and this one on Domain-Driven Design & REST.

Related

How to query arbitrary fields in Kibana?

We're importing logs that contain the the full request/response for a given endpoint. Using the escLayout c# library. The import is working fine, however the 'structured' part of the log is stored under metadata, like so:
"metadata": {
"event": {
"controller": "main",
"method": "GetData",
"request": {
"userId": 1,
"clientTypeId": 2
},
"response": {
"marketOpen": true,
"price": 18.56
}
}
}
How do I go about querying this metadata as the fields do not appear in the 'Lens' page.
Is it a case of creating an index of some description? There are a lot of different (and occasionally large) data sets so this seems really impactable.
Is querying 'ad-hoc' data like this not a good use of Kibana? Should I look elsewhere, say Grafana before I go too far down the Elastic road?
Note: We're on Elastic 8.2.0

Generating GraphQL GUI from Schema and Schema from GUI

While using GraphiQL works well, my boss has asked me to implement a user interface where users can check elements presented to them via UI elements like checkbox, map relationships and get the data and doing this will generate a graphql input for the person, call the API and get the result back to the user.
So, basically this involves 2 generations. Generating a user interface from a GraphQL schema and generating a GraphQL input query from the user's selection.
I searched and I was not able to find any tools which already do this. My server is in Node and I am using Express GraphQL. I converted my express schema to GraphQLSchema language using https://github.com/graphql-cli/graphql-cli and I introspected the GraphQLSchema language using the introspect function at https://github.com/sheerun/graphqlviz/blob/master/cli.js
The object which I got was something like this (only partial schema output given below)
`
"data": {
"__schema": {
"queryType": {
"name": "Query"
},
"mutationType": {
"name": "Mutation"
},
"subscriptionType": null,
"types": [{
"kind": "OBJECT",
"name": "Query",
"description": null,
"fields": [{
"name": "employee",
"description": null,
"args": [{
"name": "ecode",
"description": null,
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
}],
`
I am looping through the elements trying to generate UI but I am quite stuck.
What is the best way to do this? Thanks in advance.
Well for the part of generating the ui from the introspection query, I think that the response contains enough data for a sufficient ui (description for each field can be used as a placeholder for each field's input box). If you're asking how can you generate a dynamic form from the introspection response, you can take a look at other projects that created transformers from json to html forms for inspiration/usage (take a look at https://github.com/brutusin/json-forms/blob/master/README.md#cdn). For complex fields (not primitive types) you may need to do some more work.
For the schema generation from the ui, you can use any query builder tool, and build a query according to the user inputs. Each combobox will be mapped to a specific SCHEMANAME.FIELDNAME and the value will be the value of the input box.
I hope it helped a bit. BTW, it sounds like an interesting tool so let us know if you succeed!

What's the correct way to present paged resources with HAL?

This sounds like a rookie question, but I'm wondering what's the best way to present paged resources with HAL format? Right now I'm using Spring HATEOAS API to convert Page object into resource PagedResourcesAssembler#toResource(Page<T>, ResourceAssembler<T,R>). This results in the following output:
{
"_links": {
"self": {
"href": "http://example.org/api/user?page=3"
},
…
}
"count": 3,
"total": 498,
"_embedded": {
"users": [
{
"_links": {
"self": {
"href": "http://example.org/api/user/mwop"
}
},
"id": "mwop",
"name": "Matthew Weier O'Phinney"
}
]
}
}
Everything works fine but the only problem is the collection being returned is under _embedded field and has the class name, so the client has to know this class name as well right? Would it be better to just return the collection under content like non-HAL format? If yes how should I achieve it using Spring HATEOAS?
That's not a problem, that's the way _embedded is defined in the HAL specification.
users is not a class, it's a link relation that will allow clients to actually find the collection it was asking for in the first place (e.g. using a JSONPath expression). That's not something coming out of the blue at all but usually is the same link relation, the client used to find that resource in the first place.
Assume an API root exposing this document:
{
"_links": {
"users": {
"href": "…"
},
…
}
}
Seeing that, the client would have to know the semantics of users to find the link it wants to follow. In your case users is basically pointing to a collection resource that supports pagination.
So if the client follows the link named users, it can then find the actual content it's looking for under _embedded.users in the HAL response by combining knowledge about the media type (HAL, _embedded) and the service's application-level semantics (users).

ember-data - best strategy for loading complex data structures

I am using ember-data 2.0. I want to load all data from the server at startup. Then the app is really fast after the initial loading. The application is mobile, and may have varying bandwidth. I want to load the data as fast as possible. I want to use JSON API to comply with the newest ways of using ember-data.
Each object is small, just a handful of attributes. But there may be 200 such objects to load.
Is it best to do many small ajax calls or one big one? I imagine it is faster to use one big call that contains all my objects, but is that possible with the JSON API and the out-of-the-box adapters?
Of course, I could just use findAll() but that will only load all objects of one type. I have several object types in my model that are connected with hasMany and belongsTo relationships.
If I use the RestAdapter out of the box, that will result in many ajax calls, right?
What is the best strategy to use and how to implement that with ember-data and the adapters?
You can load different types to the store from single payload out of the box with Ember Data. By default JSON serializer assumes that each root node in payload corresponds to a type.
Let's say you have models:
/models/post.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
comments: DS.hasMany('comment');
});
/models/comment.js
import DS from 'ember-data';
export default DS.Model.extend({
comment: DS.attr('string'),
post: DS.belongsTo('post');
});
And you have an endpoint /posts which responds with payload like this:
{
"posts": [
{
"id": 1,
"title": "Post 1",
"body": "Post 1 body",
"comment_ids": [1, 2]
},
{
"id": 2,
"title": "Post 2",
"body": "Post 2 body",
"comment_ids": [3]
}
],
"comments": [
{
"id": 1,
"comment": "Comment 1",
"post_id": 1
},
{
"id": 2,
"comment": "Comment 2",
"post_id": 1
},
{
"id": 3,
"comment": "Comment 3",
"post_id": 2
}
]
}
So when you do store.findAll('post'), Ember Data will request /posts endpoint, recieve the payload and push both posts and comments to the store. And all relations will be resolved properly.
But there are some notes:
if you define model relation with {async: true}, Ember data will always hit the server to fetch relation records.
Everywhere in the app you would need to use store.peek() and store.peekAll() instead of store.find() and store.findAll() in order to get records from the store but not from server.

Pull public event data from Google Calendar

I may be over thinking this a bit. On my web site, I would like to user certain data from my public google calendar. My plan is to pull it on the server side so I can do things like process it, cache it and format it the way I want.
I've been looking at using the Google Api libraries, but I can't get past any of the authorization hurdles. A service account sounds like what I really want, but I'm having trouble wrapping my head around how that works in this situation.
The old GDATA apis would be ok, but I'm not very keen on using them because they look fairly deprecated at this point by the newer libraries.
Since it is all public data, I'm hoping there is a simpler way to get to the event data that I'm looking for.
In case it matters, my site is Asp.Net (MVC).
Update
Ok, I was definitely way over thinking it. See my answer.
Now that RSS has been removed from Google Calendar, I've been in search of an easy replacement. I dug around and found the following in the Google Calendar API that seems to do the trick: calendar.events.list
Calendar Events List in Google API Explorer is a good place to get started with the different parameters and options - and it'll build you an example request string. You can see that I specified a minimum time of 2/5/2016, sort it by the start time, and show deleted events.
GET https://www.googleapis.com/calendar/v3/calendars/[CALENDAR ID HERE]/events?
orderBy=startTime&showDeleted=true&singleEvents=true&
timeMin=2016-02-05T00%3A00%3A00Z&key={YOUR_API_KEY}
Results are in JSON so you can parse it in your favorite programming language, ASP.NET or whatever. Result looks like:
{
"kind": "calendar#events",
"etag": "\"123456789123456\"",
"summary": "My Public Calendar",
"updated": "2016-01-29T14:38:29.392Z",
"timeZone": "America/New_York",
"accessRole": "reader",
"defaultReminders": [ ],
"items": [ {
"kind": "calendar#event",
"etag": "\"9876543210987654\"",
"id": "sfdljgsdkjgheakrht4sfdjfscd",
"status": "confirmed",
"htmlLink": "https://www.google.com/calendar/event?eid=sdgtukhysrih489759sdkjfhwseihty7934hyt94hdorujt3q95uy689u9yhfdgnbiwe5hy",
"created": "2015-07-06T16:21:59.000Z",
"updated": "2015-07-06T16:21:59.329Z",
"summary": "In-Service Day",
"location": "Maui, HI",
"creator": {
"email": "abra#cadabra.com",
"displayName": "Joe Abra"
},
"organizer": {
"email": "cadabra.com_sejhrgtuiwerghwi4hruh#group.calendar.google.com",
"displayName": "My Public Calendar",
"self": true
},
"start": {
"date": "2016-02-08"
},
"end": {
"date": "2016-02-09"
},
"transparency": "transparent",
"iCalUID": "isdt56y784g78ty86tgsfdgh#google.com",
"sequence": 0
},
{
...
}]
}
One good answer to this (the one I'm going with) is to simply use the calendar's public address to get the data. This is an option that I had forgotten about and it works fine for this particular situation.
You can find the url for the data if you go to the settings for a particular calendar and pick the format you want (I went with xml for this situation.)
The data that you get out of this service is very human-reader optimized, but I can make it work for what I'm doing.

Resources