Reverse relationships in Prismic - rest

Suppose I have a simple blog with the data type of Article and the data type of ArticleTag:
Article ->
title - Title field
tag - Content relationship to ArticleTag
ArticleTag ->
title - Title field
icon - Text field
For that purpose, I would like to return query all ArticleTags and get each with N Articles (or even all of them), but the API documentation (both GraphQL and REST) is awfully silent on how to expand reverse content relationships. i.e. they only specify how to get fields from ArticleTag per Article (or how to get all Articles with a specific ArticleTag per id which is strange but whatever)
I can think of a workaround: query all tags, then for each tag query all articles. Thing is that this sounds awfully slow as it generates N+1 API requests for the number of tags I have, plus, this may be happening on the client-side as well in this project! So I'd rather avoid that if in any way possible.

Yeah the workaround you presented is the only way to do that.

Related

Pragmatic URLs vs. recommended URLs

I have Book resources and Author resources. They're connected, because - obviously - an Author wrote a Book, so the GET Book URL is like:
GET: /authors/{author_name}/books/{book-title}
And this is fine.
I'm puzzled however when it comes to creating (POST) the related resources (in this case, a Book), and can't find anything on the subject in the Symfony area. There are two possibilities:
A REST recommended one:
POST: /authors/{author_name}/books/{book_title}
A Symfony pragmatic one - just:
POST: /books
The latter one with additionally sent author and title within the form - which are not needed in the former one.
The usual way how it is done in Symfony is through use of forms, which I'm using. When I take the pragmatic approach, everything's fine. All the data, including author and book's title are NOT a part of the URL - everything is in the sent form.
The problem is when I would like to take on the REST recommended approach. Then data are split: some come into form, and some other are part of URL.
Let's assume I wanted to choose that "elaborative" URL with some key data in it. How do I "merge" form data BEFORE the form is validated?
(Note also that I can't require the "title" and the "author" fields in the form, though they in fact ARE required when saving the Book to database).
A REST recommended one:
POST: /authors/{author_name}/books/{book_title}
First, I totally disagree that this is the "REST recommended" way. Assuming book_title is your resource identifier, the recommend way would be:
POST: /authors/{author_name}/books
With book_title part of the payload of the request.
Second, I also think it's a big mistake to use author_name and book_title as identifier. What if they change? What about books and authors with the same name? What if a book as multiple authors?
So to answer your question, you don't have a problem because the "REST recommended" approach is the "pragmatic" approach.
Examples:
GET /books/{id}
POST /books
GET /authors/{id}
POST /authors

Is it possible to group multiple collections in mongodb

so I'm working with a database that has multiple collections and some of the data overlaps in the collection . In particular I have a collection called app-launches which contains a field called userId and one called users where the _id of a particular object is actually the same as the userId in app-launches. Is it possible to group the two collections together so I can analyze the data? Or maybe match the the userId in app-launches with the _id in users?
There is no definit answer for your question Jeffrey and none of the experts here can tell you to choose which technique over other just by having this information.
After going through various web pages over internet and mongo documentation and understanding the design patterns used in Mongo over a period of time, How I would design it depends on few things which I can try explaining it here in short.
if you have a One-To-One relation then always prefer to choose Embedding over Linking. e.g. User and its address (assuming user has only one address) thus you can utilize the atomicity (without worrying about transactions) as well easily fetch the records without too and fro to bring other information as in the case of Linking (like in DBRef)
If you have One-To-Many relation then you need to consider whether you can do the stuff by using Embedding (prefer this as explained the benefits in point 1). However, embedding would help you if you always want the information altogether e.g. Post/Comments where your requirement is to get the post and all of its comments by postId let say. But think of a situation where you need to get all the comments (and it related posts) which contains some specific tags in comments. in this case you should prefer Linking Because if you go via Embedding route then you would end up getting all the collection of comments for a post and you have to filter the desired comments.
for a Many-To-Many relations I would prefer two separate entities as well another collection for linking them e.g. Product-Category.
-$

Breeze: complex graph returns only 1 collection

I have a physician graph that looks something like this:
The query I use to get data from a WebApi backend looks like this:
var query = new breeze.EntityQuery().from("Physicians")
.expand("ContactInfo")
.expand("ContactInfo.Phones")
.expand("ContactInfo.Addresses")
.expand("PhysicianNotes")
.expand("PhysicianSpecialties")
.where("ContactInfo.LastName", "startsWith", lastInitial).take(5);
(note the ContactInfo is a pseudonym of the People object)
What I find is that If I request Contact.Phones to be expanded, I'll get just phones and no Notes or Specialties. If I comment out the phones I'll get Contact.Addresses and no other collections. If I comment out ContactInfo along with Phones and Addresses I'll get Notes only etc. Essentially, it seems like I can only get one collection at a time.
So, Is this a built in 'don't let the programmer shoot himself in the foot'?? safeguard or do I have to enable something?
OR is this graph too complicated?? should I consider a NoSql object store??
Thanks
You need to put all your expand clauses in a single one like this:
var query = new breeze.EntityQuery().from("Physicians")
.expand("ContactInfo, ContactInfo.Phones, ContactInfo.Addresses, PhysicianNotes, PhysicianSpecialties")
.where("ContactInfo.LastName", "startsWith", lastInitial).take(5);
You can see the documentation here: http://www.breezejs.com/sites/all/apidocs/classes/EntityQuery.html#method_expand
JY told you HOW. But BEWARE of performance consequences ... both on the data tier and over the wire. You can die a miserable death by grabbing too widely and deeply at once.
I saw the take(5) in his sample. That is crucial for restraining a runaway request (something you really must do also on the server). In general, I would reserve extended graph fetches of this kind for queries that pulled a single root entity. If I'm presenting a list for selection and I need data from different parts of the entity graph, I'd use a projection to get exactly what I need to display (assuming, of course, that there is no SQL View readily available for this purpose).
If any of the related items are reference lists (color, status, states, ...), consider bringing them into cache separately in a preparation step. Don't include them in the expand; Breeze will connect them on the client to your queried entities automatically.
Finally, as a matter of syntax, you don't have to repeat the name of a segment. When you write "ContactInfo.Phones", you get both ContactInfos and Phones so you don't need to specify "ContactInfo" by itself.

Is there a better restful interface for this?

GET https://api.website.com/v1/project/employee;company-id={company-id},
title={title-id}?non-smoker={true|false}&<name1>=<value1>&<name2>=<value2>&<name3>=<value3>
where:
company-id is mandatory,
title is optional
name/value can be any filter criteria.
Is there a better way to define the interface?
This API is not supposed to create an employee object. It is for getting an array of employee objects that belongs to a particular company and has a particular title and the other filter criteria.
I don't know if there is a better way, because it depends often on the technology you use and its idioms.
However, here is two different URI designs that I like (and why)
#1 GET https://api.website.com/v1/project/employee/{company-id}?title={title-id}&non-smoker={true|false}&<name1>=<value1>&<name2>=<value2>&<name3>=<value3>
#2 GET https://api.website.com/v1/project/company/{company-id}/employee?title={title-id}&non-smoker={true|false}&<name1>=<value1>&<name2>=<value2>&<name3>=<value3>
As you can see in both example I extracted company-id from the query string. I prefer to add mandatory parameters in the path info to distinguish them. Then, in the second URI, the employee ressource is nested in the company. That way you can easily guess that you can retrieve all employee from a specific company, which is not obvious in the first example.
This api is supposed to GET employee objects that satisfy the given criteria of belonging to a particular company, having particular job title and some other filter criteria.
Personally I would just design your URI as http://acme.com/employee/?company=X&title=Y&non-smoker=Z&T=U. I wouldn't write "in stone" that the company is mandatory: your API will be easier to change.
However, you should consider that few "big" requests are far faster than plenty of small ones. Moreover, URI representations can be effectively cached. Therefore it is often better to have URIs based on IDs (since there are more chances that they will be asked again).
So you could get the complete employee list of a company (plus other data about the company itself) with http://acme.com/company/X and then filter it client-side.
Are you creating a new employee object? If so then a POST (create) is more appropriate. A good clue is all the data you're pushing in the URL. All that should be in the body of the POST object.

How to design a Restful API with the resource hierarchy?

There are products and reviews of products.
So, I can get product list like this...
GET /products
also I can fetch one product or reviews or the product like this...
GET /products/{productID}
GET /products/{productID}/reviews
Those are clear. but the problem happens when I want to get all reviews I wrote.
I could create uri like this..
1. GET /products/reviews?author=myId
or
2. GET /reviews?author=myID
However, the problem of first one comes from conflict between {productID} and reviews.
the problem of next one comes from relation products and reviews because reviews should be under the products according to the hierarchy.
How can I get all reviews I wrote with RESTful API?
usually the route is like this
GET /products/:product_id/reviews?author=myID
so the parameters are
- product_id
- author
with that, you will get all the reviews for a certain product and author.
Though, if you want all of your reviews, then this is correct:
GET /reviews?author=myID
To get all reviews written by a given author for all products, a RESTful way to do this would be
GET /authors/{authorId}/reviews
If you want to get all reviews written by a given author for a single product, then you could use
(a) GET /authors/{authorId}/products/{productId}/reviews
I like this approach over specifying productId or authorId in the query string. Authors contain products, and products contain reviews, so this is a nice RESTful URL. But if you want to use query string, then you could use either of the following:
(b) GET /products/{productId}/reviews?authorId={authorId}
(c) GET /authors/{authorId}/reviews?productId={productId}
But I personally prefer option (a) over options (b) or (c). I think it describes the object hierarchy in a cleaner way.
I would use the second one if I were you, since flat URIs are usually shorter than hierarchical ones and shorter URIs are easier to route: it is harder to mistype the URI template accidentally.
So using
GET /reviews?author={myID}
GET /reviews?product={productID}
is ok too. (If you have different review types, maybe it is better to use product-reviews instead of just reviews.)
Just to avoid misunderstandings REST does not have URI structure constraints, those are implementation details, so you can use both your proposed URIs. You should document them and apply the HATEOAS constraint.