I have a very simple example using Spring Data Rest and JPA which exposes a person resources. When launching the application it works as expected and I can POST and GET instances of the resource.
When sending a GET against /person I get the following response:
"_embedded": {
"person": [
{
"firstName": "FN",
"lastName": "LN",
"_links": {
"self": {
"href": "http://localhost:9090/person/1"
},
"person": {
"href": "http://localhost:9090/person/1"
},
"address": {
"href": "http://localhost:9090/person/1/address"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:9090/person{?page,size,sort}",
"templated": true
},
"profile": {
"href": "http://localhost:9090/profile/person"
},
"search": {
"href": "http://localhost:9090/person/search"
}
},
"page": {
"size": 20,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}
As you can see the person resource has a firstName attribute with a value of FN.
My question is should the following GET query work out of the box?
/person?firstName=FN
or is this something that needs to be implemented with a custom search method?
Needless to say it isn't working for me but I'm seeing conflicting information as to if it is supported out of the box.
Thanks in advance,
My question is should the following GET query work out of the box?
No. You will get an error like
{
"cause": {
"cause": null,
"message": "For input string: \"findByName\""
},
"message": "Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'findByName'; nested exception is java.lang.NumberFormatException: For input string: \"findByName\""
}
Spring Data Rest has the following URL structure.
/{pluralEntityName}/{primaryKey} e.g when the entity name is Person and the primary key is Long it will be /persons/1
We see this error message because Spring Date Rest tries to convert the second argument after the entity name to the primary key of that entity. In my Person entity, the primary key is Long, so It tries to convert findByName to Long and fails.
or is this something that needs to be implemented with a custom search method?
Yes, if you want to do a search on the repository you need to write a method in the repository following Spring Data JPA's method name conventions then Spring Data JPA will automatically convert this method to an SQL query and Spring Data Rest will automatically expose this method as an endpoint.
e.g If you write a method like:
List findByNameContains(String name);
This method will be exposed with Spring Data Rest and you will be able to access it from the following endpoint:
http://localhost:8080/persons/search/findByNameContains?name=Mahsum
Btw, you can see all available search method by visiting http://localhost:8080/persons/search
Related
I have a GraphQL query that calls a REST service to get the return object. The query contains an Id parameter that is then passed to the service. However, the REST service can respond with http status 404 Not Found if an object with that Id does not exist. That seems like the right response.
How do you model a Not Found response in GraphQL?
Is there a way to inform the GQL caller that something does not exist?
Update
Some options I am considering:
Return null
Change the GrqlhQL Query to return a list of objects and return empty list of nothing is found
Return some kind of error object with an error code
but it is unclear if there is a recommended practice in GQL API design.
You might treat it as an error and handle it accordingly.
I recommend you to check the GraphQL spec, the paragraph about error handling.
I hope it contains exactly what you are looking for.
Basically, you should return whatever you could, and inform a client about potential problems in the "errors" field.
The example from the documentation:
Request:
{
hero(episode: $episode) {
name
heroFriends: friends {
id
name
}
}
}
Response:
{
"errors": [
{
"message": "Name for character with ID 1002 could not be fetched.",
"locations": [ { "line": 6, "column": 7 } ],
"path": [ "hero", "heroFriends", 1, "name" ]
}
],
"data": {
"hero": {
"name": "R2-D2",
"heroFriends": [
{
"id": "1000",
"name": "Luke Skywalker"
},
{
"id": "1002",
"name": null
},
{
"id": "1003",
"name": "Leia Organa"
}
]
}
}
}
I am providing access to a REST endpoint where some aggregates are computed.
Let's say the model is as follows:
Purchase:
amount: amount spent
group: one of ELECTRONICS, FOOD, FURNITURE, ...
date: purchase date
Now I want to offer a timeline of purchases, aggregated on a weekly basis, and partitioned by group. This will produce the following data:
{
"ELECTRONICS": [{"week": "2018WK1", "amount": 1000.0}, ...],
"FOOD": [{"week": "2018WK1", "amount": 2000.0}, ...],
"FURNITURE": [{"week": "2018WK1", "amount": 3000.0}, ...],
...
}
Some things to note:
the number of groups is not known in advance (it depends on the stored data)
since this is computed data, I would like to return the whole thing in one single request, instead of having to do the aggregates for each of the groups in separate requests
The URL for the request would be something like: /api/weekly_purchases/2018
How can I offer these kind of resources in a REST API?
Return several resources in REST call
How would you do it as a web page?
Somewhere on your web site would be a link, with text "this week's summary" (or whatever the appropriate concept is in the language of your domain). If a user clicked that link, the browser would do a GET on one URL, which would go to the server, aggregate all of the data together, and return the result.
So do that?
REST doesn't care about the spelling of the URI (the browser doesn't try to interpret the URL, except in very shallow generic ways), so /api/weekly_purchases/2018 is fine.
The trick is recognizing that a report summarizing purchases in the current fiscal year, broken out by week, is a resource. It may have data in it that duplicates the information in other resources, even data in many other resources, but it is still a resource itself.
As already mentioned in my initial comment or by VoiceOfUnreason the same techniques that apply to the browser-based Web apply to any interaction model used by applications that follow the REST architecture principles. As also mentioned by VoiceOfUnreason a client would initially request some state returned from the entry-point, i.e. https://api.acme.com that will return a collection of links a client can use to progress its task. In order for the client to determine which URL to invoke the response should give the URI a meaningful name (link-relation name). IANA maintains a list of already specified link-relation names you should use if possible or define your own one in further standards. According to Fielding the specification of media-types and link relations is one of the most important things to do if developing a RESTful architecture.
For simplicity I use a simplified HAL-JSON syntax throughout the example.
{
...
"_links": {
"self": {
"href": "https://api.acme.com"
},
...
"archives": {
"href": "https://api.acme.com/weekly_purchases"
},
...
}
}
According to the HTML 5 spec archives
indicates that the referenced document describes a collection of records, documents, or other materials of historical interest
The link relation name therefore describes the intent of the URI which client can use if interested in retrieve a collection of historical entries. The client does not really have to know the exact URI as he will learn it by simply following the link relation's target href element. This allows the server to change its internal URI structure anytime it has to without actually breaking clients.
On following the archives target URI a client will not really know yet how the actual data has to be retrieved as the URI and the link relation name are to generic. But the server will guide the client through its task. A response on the invocation of the abovementioned target URI might return the following content:
{
"year": [
"2018": {
"_links": {
"chapter": {
"href": "https://api.acme.com/weekly_purchases/2018"
}
}
},
"2017": {
"_links": {
"chapter": {
"href": "https://api.acme.com/weekly_purchases/2017"
}
}
},
...
"2014": {
"_links": {
"chapter": {
"href": "https://api.acme.com/weekly_purchases/2014"
}
}
}
],
"_links": {
"self": {
"href": "https://api.acme.com/weekly_purchases"
},
"first": {
"href": "https://api.acme.com/weekly_purchases"
},
"next": {
"href": "https://api.acme.com/weekly_purchases?p=1"
},
"last": {
"href": "https://api.acme.com/weekly_purchases?p=3"
},
"current": {
"href": "https://api.acme.com/weekly_purchases"
}
}
}
This response basically only teaches the client that there are multiple years available to choose from and the client has to decide which year s/he is interested in an invoke that URI to proceed its task. The next, last and first link relation indicate that there are multiple pages available as only the 5 years per page are returned. The current link relation name will always point to the most recent entry in the collection, which is the initial page (or first page) of the collection-resource. Note further how multiple different link-relation names may point to the same URI. Sometimes it isn't really clear which link relation names to use as their semantics partly overlap. This is just an example on what can be done with link relation names.
A client can now further drill down to the purchases done in 2018 by following the chapter link for 2018. A response on invoking that URI may now look like this:
{
"purchase": [
"W1": {
"sum": 1263.59,
"currency": "Euro",
"_links": {
"about": {
"href": "https://api.acme.com/weekly_purchases/2018/1"
}
}
},
"W2": {
"sum": 569.32,
"currency": "Euro",
"_links": {
"about": {
"href": "https://api.acme.com/weekly_purchases/2018/2"
}
}
},
...
"W48": {
"sum": 72.98,
"currency": "Euro",
"_links": {
"about": {
"href": "https://api.acme.com/weekly_purchases/2018/48"
}
}
},
"current": {
"sum": 72.98,
"currency": "Euro",
"_links": {
"about": {
"href": "https://api.acme.com/weekly_purchases/2018/48"
}
}
}
],
"_links": {
"index": {
"href": "https://api.acme.com/weekly_purchases"
},
"self": {
"href": "https://api.acme.com/weekly_purchases/2018"
},
"current": {
"href": "https://api.acme.com/weekly_purchases/2018"
},
"prev": {
"href": "https://api.acme.com/weekly_purchases/2017"
},
"prev-archive": {
"href": "https://api.acme.com/weekly_purchases/2017"
},
"first": {
"href": "https://api.acme.com/weekly_purchases/2000"
}
}
}
You could either add content here to the weekly summary or hide it down the road by following the about link only if clients are really interested in such details.
Note further: As weekly_purchases is just a string without meaning to the client it does not really know what it means. You could therefore also rename it to purchase-archive or something like that and introduce a further choice to the client and let the client determine whether it wants a weekly, monthly or total summary of that year.
REST is about providing choices to a client and teach it what the actual choices are intended for. One of the aims the RESTful architecture tries to solve is the strict coupling between clients and servers which prevent the latter one from evolving freely and the former ones to break if the latter one changes unexpectedly. This decoupling only works if certain standards are used to increase the likelihood for interoperability. Usually out-of-band information (pre-existing knowledge about the API and how to interact with it) is leading to a coupling. Even Fielding stated that some prior knowledge is needed though but not encoded directly into the application but on reusing certain standards like well-defined and stable media-types and link-relation names.
I'm trying to validate that the data I am returned it sensible. Validating data types is done. Now I want to validate that I've received all of the data needed to perform a task.
Here's a representative example:
{
"things": [
{
"id": "00fb60c7-520e-4228-96c7-13a1f7a82749",
"name": "Thing 1",
"url": "https://lolagons.com"
},
{
"id": "709b85a3-98be-4c02-85a5-e3f007ce4bbf",
"name": "Thing 2",
"url": "https://lolfacts.com"
}
],
"layouts": {
"sections": [
{
"id": "34f10988-bb3d-4c38-86ce-ed819cb6daee",
"name": "Section 1",
"content:" [
{
"type": 2,
"id": "00fb60c7-520e-4228-96c7-13a1f7a82749" //Ref to Thing 1
}
]
}
]
}
}
So every Section references 0+ Things, and I want to validate that every id value returned in the Content of Sections also exists as an id in Things.
The docs for Object.assert(..) implies that I need a concrete reference. Even if I do the validation within the Object.keys or Array.items, I can't resolve the reference at the other end.
Not that it matters, but my context is that I'm validating HTTP responses within IcedFrisby, a Frisby.js fork.
This wasn't really solveable in the way I asked (i.e. with Joi).
I solved this for my context by writing a plugin for icedfrisby (published on npm here) which uses jsonpath to fetch each id in Content and each id in Things. The plugin will then assert that all of the first set exist within the second.
I'm trying to identify the Parent Id for a list item.
I'm making the following call;
https://{sitecollection}/{personal_site}/_api/Web/Lists(guid'blabla')/Items(blabla)?$select=ParentUniqueId
But it is giving me the following error;
{
"error": {
"code": "-1, Microsoft.SharePoint.SPException",
"message": {
"lang": "en-US",
"value": "The field or property 'ParentUniqueId' does not exist."
}
}
}
The same issue is with "ParentLeafName" and some others.
However, when I get the /fields (meta of fields for a list) for this list, it mentions this field along with others, which means I'm doing the right call as I'm successfully getting other fields like
https://{sitecollection}/{personal_site}/_api/Web/Lists(guid'blabla')/Items(blabla)?$select=ServerUrl
Result
{
"d": {
"__metadata": {
"id": "blabla",
"uri": "blabla",
"etag": "\"10\"",
"type": "SP.Data.DocumentsItem"
},
"ServerUrl": "/personal/{site}/{filepath}"
}
}
One thing I have noticed though, that these fields are case sensitive, that is, if i write "serverurl" it gives me the same error. Is this a case issue with "ParentUniqueId" field?
Unfortunately ListItem resource in SharePoint 2013 REST interface does not expose ParentUniqueId property.
But you could use the following query to return ParentUniqueId property for ListItem:
/_api/Web/Lists/getByTitle('<list title>')/items(<item id>)/FieldValuesAsText?$select=ParentUniqueId
References
Lists and list items REST API reference
I'm designing a REST api and to be as Restful as it gets I want to implement HATEOAS into the json responses.
If the linked entities are not present in database say for example every user has a passport entity but if someone doesn't have then i want to send the set of rel and href links like this:
{
"links": [
{
"rel": "drivingLicence",
"href": "http://localhost:9090/api/v1/drivingLicence/6"
},
{
"rel": "passport",
"href": null
},
{
"rel": "self",
"href": "http://localhost:9090/api/v1/user/4028818347818fd80147819111d60001"
}
],
"userId": "4028818347818fd80147819111d60001",
"userName": "username",
"fullName": "Some User",
"activeFlag": "ACTIVE",
"createTimestamp": 1406628074000,
"updateTimestamp": 1505697126548
}
Is there any way to achieve this using Spring HATEOAS or manually i have to check for null and then set href as null.
There's no way to do this with the built in Link class as it doesn't let href be null or empty (checks in constructor). Perhaps you can derive from Link and pass in non-empty href, but override the getHref to return null.
FWIW: i've never seen the href as null strategy. I've seen have the link, and if it returns 404 then that means it's not present & just not have the link. As a hypermedia client, i'd be really surprised to see href of null...but this is a new field with new practices happening all the time.