REST api, POST entity with relationships? - api

Im having an issue where I cant decide how to procced on this matter.. and I need to know if there is any standard way to solve this.. or if you guys have any great input for this matter.
The thing is that I have started to build a very basic API for learning purpose
The API is a simple Music store.. where the store has some Albums which requires and artist.
So the Relationship is Artist <--- 1 ----- * ---> Albums and for an album to exist its required that that the album has an artist. But the artist doesnt require and Album.
Now to the problem...
Due to this relationship if I want to create a new Album.. I would have to post the album data.. AND the entire Arist-data..not just the ID of th artist.. but the whole Artist.. which doesnt seem very effective if you ask me.. since that a whole lot of unnecessary.
So as I see it there is two ways to solve this...
either I just post the entire album-data/object and allows the Artist-data for the object to only contain an ID which then reference to the artist.
So instead of posting:
{
"Name":"AlbumName",
"Description":"Some description for the album",
"ReleaseYear": "1992",
"Artist" {
"Name":"Some artist",
"Id":"12345",
"Biography":"Lorem ipsum dolor sit amet"
}
}
I would do this:
{
"Name":"AlbumName",
"Description":"Some description for the album",
"ReleaseYear": "1992",
"Artist" {
"Id":"12345"
}
}
Option number two is to actually have a route/url thats specific for this...
for instance:
/api/artist/{artistid}/album
And then simply post an album-object to that url..
But as I said.. Im really not sure of whats right and wrong here.. or is there any standard way of handling this?
Thanks in advance!

I would suggest something like this.
POST /musicstore/artist/343/albums
{
"Name":"AlbumName",
"Description":"Some description for the album",
"ReleaseYear": "1992",
}
The act of creating a resource as a child of the collection of albums for the artist 343 implicitly creates the relationship between the artist and the album. There is no need to specify it in the payload.

Albums and Artists are two separate entities, you shouldn't post all the artist data into Albums, just its ID.
Therefore you first create the artist if it doesn't exist, and after that you post the album details, artist_id being one of its properties.

Related

Get ratings for an item via API - Podio

I'd like to get information about a rating (fivestars) of one of an app item.
I've tried to do it using two requests:
/rating/item/1********9
and
/item/1********9?mark_as_viewed=false
Both via https://developers.podio.com/.
I'm receiving only the response (related to ratings):
"ratings":{
"like":{
"average":null,
"counts":{
"1":{
"total":0,
"users":[
]
}
}
}
},
In the GUI I can see my vote (3 stars).
Could you please help me with how I could get the rating?
Thanks for your help!
Adding a star rating to a Podio app is actually creating a Voting object (I know it's not very intuitive). I believe the endpoint you're looking for is Get result of voting on an item.

Directus - how to show Many2Many relationship in api

I am trying to make a blog in Directus.
I created Blog Collection and Categories Collection.
I am using junction table with many to many relationship to connect categories to blog.
I can create a new blog post and select category from category collection and I can add a new category also.
But when I am calling in api, it is not showing the category field in my rest api call.
I can call category endpoint and view the list of all the categories in rest api but in blog collection endpoint, I cant view related category name.
I want to view all the selected category name to each blog posts in my rest api.
And I want to view all the blog posts when I call category collection in my rest api by putting category name like projectname/items/categories/aliens/ so I can see all the blog posts of aliens categories.
Currently I am getting this by calling my blog collection in json -
{
"data": [
{
"id": 1,
"status": "published",
"owner": 1,
"created_on": "2020-03-16 21:15:25",
"blog_title": "first blog post title",
"blog_content": "<p>sdlkjfhsdkfol8ysdmfhj sd,fh klsdhf msoiudf oihsdyfghm soreht4,7shetc,oiuh,scenclkr</p>\n<p><strong>dsfgdsfgds</strong></p>"
}
]
}
How to get the category name on rest api ?
Did you try using the fields parameter? This is used to fetch deeply nested relational data:
?fields=*.*.*
In this example, the asterisk is a wildcard for_all_ fields at that relational depth... so this fetches three levels deep.
https://docs.directus.io/api/query/fields.html
You should have a relational table created between those 2 tables so you should be able to filter the information like this ?fields=id,blog_title,blog_content,category.category_id.category_name,category.category_id.status
In case this is confusing let me try to simplify the relationship part:
category.category_id.category_name
<field_name_on_current_item>.<identifier_on_junction_table_related_to_category_id>.<relation_field_name_to_display>
I realise that this is an old post, but it might help someone looking for the answer.
To select only the relational data use
?fields=category.*
This shows only the related category field of the blog article.

How to construct intersection in REST Hypermedia API?

This question is language independent. Let's not worry about frameworks or implementation, let's just say everything can be implemented and let's look at REST API in an abstract way. In other words: I'm building a framework right now and I didn't see any solution to this problem anywhere.
Question
How one can construct REST URL endpoint for intersection of two independent REST paths which return collections? Short example: How to intersect /users/1/comments and /companies/6/comments?
Constraint
All endpoints should return single data model entity or collection of entities.
Imho this is a very reasonable constraint and all examples of Hypermedia APIs look like this, even in draft-kelly-json-hal-07.
If you think this is an invalid constraint or you know a better way please let me know.
Example
So let's say we have an application which has three data types: products, categories and companies. Each company can add some products to their profile page. While adding the product they must attach a category to the product. For example we can access this kind of data like this:
GET /categories will return collection of all categories
GET /categories/9 will return category of id 9
GET /categories/9/products will return all products inside category of id 9
GET /companies/7/products will return all products added to profile page of company of id 7
I've omitted _links hypermedia part on purpose because it is straightforward, for example / gives _links to /categories and /companies etc. We just need to remember that by using hypermedia we are traversing relations graph.
How to write URL that will return: all products that are from company(7) and are of category(9)? In otherwords how to intersect /categories/9/products and /companies/7/products?
Assuming that all endpoints should represent data model resource or collection of them I believe this is a fundamental problem of REST Hypermedia API, because in traversing hypermedia api we are traversing relational graph going down one path so it is impossible to describe such intersection because it is a cross-section of two independent graph paths.
In other words I think we cannot represent two independent paths with only one path. Normally we traverse one path like A->B->C, but if we have X->Y and Z->Y and we want all Ys that come from X and Z then we have a problem.
So far my proposition is to use query strings: /categories/9/products?intersect=/companies/9 but can we do better?
Why do I want this?
Because I'm building a framework which will auto-generate REST Hypermedia API based on SQL database relations. You could think of it as a trans compiler of URLs to SELECT ... JOIN ... WHERE queries, but the client of the API only sees Hypermedia and the client would like to have a nice way of doing intersections, like in the example.
I don't think you should always look at REST as database representation, this case looks more of a kind of specific functionality to me. I think I'd go with something like this:
/intersection/comments?company=9&product=5
I've been digging after I wrote it and this is what I've found (http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api):
Sometimes you really have no way to map the action to a sensible RESTful structure. For example, a multi-resource search doesn't really make sense to be applied to a specific resource's endpoint. In this case, /search would make the most sense even though it isn't a resource. This is OK - just do what's right from the perspective of the API consumer and make sure it's documented clearly to avoid confusion.
What You want to do is to filter products in one of the categories ... so following Your example if we have:
GET /categories/9/products
Above will return all products in category 9, so to filter out products for company 7 I would use something like this
GET /categories/9/products?company=7
You should treat URI as link to fetch all data (just like simple select query in SQL) and query parameters as where, limit, desc etc.
Using this approach You can build complex and readable queries fe.
GET /categories/9/products?company=7&order=name,asc&offset=10&limit=20
All endpoints should return single data model entity or collection of
entities.
This is NOT a REST constraint. If you want to read about REST constraints, then read the Fielding dissertation.
Because I'm building a framework which will auto-generate REST
Hypermedia API based on SQL database relations.
This is a wrong approach and has nothing to do with REST.
By REST you describe possible resource state transitions (or operation call templates) by sending hyperlinks in the response. These hyperlinks consist of a HTTP methods and URIs (and other data which is not relevant now) if you build the uniform interface using the HTTP and URI standards, and we usually do so. The URIs are not (necessarily) database entity and collection identifiers and if you apply such a constraint you will end up with a CRUD API, not with a REST API.
If you cannot describe an operation with the combination of HTTP methods and already existing resources, then you need a new resource.
In your case you want to aggregate the GET /users/1/comments and GET /companies/6/comments responses, so you need to define a link with GET and a third resource:
GET /comments/?users=1&companies=6
GET /intersection/users:1/companies:6/comments
GET /intersection/users/1/companies/6/comments
etc...
RESTful architecture is about returning resources that contain hypermedia controls that offer state transitions. What i see here is a multistep process of state transitions. Let's assume you have a root resource and somehow navigate over to /categories/9/products using the available hypermedia controls. I'd bet the results would look something like this in hal:
{
_links : {
self : { href : "/categories/9/products"}
},
_embedded : {
item : [
{json of prod 1},
{json of prod 2}
]
}
}
If you want your client to be able to intersect this with another collection you need to provide to them the mechanism to perform this. You have to give them a hypermedia control. HAL only has links, templated links, and embedded as control types. let's go with links..change the response to:
{
_links : {
self : { href : "/categories/9/products"},
x:intersect-with : [
{
href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 1",
title : "Company 6 products"
},
{
href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 2",
title : "Company 5 products"
},
{
href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 3",
title : "Company 7 products"
}
]
},
_embedded : {
item : [
{json of prod 1},
{json of prod 2}
]
}
}
Now the client just picks the right hypermedia control (aka link) based on the title field of the link.
That's the simplest solution. But you'll probably say there's 1000's of companies i don't want 1000's of links...well ok if that;s REALLY the case...you just offer a state transition in the middle of the two we have:
{
_links : {
self : { href : "/categories/9/products"},
x:intersect-options : { href : "URL to a Paged collection of all intersect options"},
x:intersect-with : [
{
href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 1",
title : "Company 6 products"
},
{
href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 2",
title : "Company 5 products"
},
{
href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 3",
title : "Company 7 products"
}
]
},
_embedded : {
item : [
{json of prod 1},
{json of prod 2}
]
}
}
See what i did there? an extra control for an extra state transition. JUST LIKE YOU WOULD DO IF YOU HAD A WEBPAGE. You'd probably put it in a pop up, well that's what the client of your app can do too with the result of that control.
It's really that simple...just think how you'd do it in HTML and do the same.
The big benefit here is that the client NEVER EVER needed to know a company or category id or ever plug that in to some template. The id's are implementation details, the client never knows they exist, they just executed Hypermedia controls..and that is RESTful.

Django one-to-many queries

Django newbie here.
I created three models: Band, Album and AlbumType (Live, EP, LP). Album have two foreign keys (from band and albumtype). Ok, so, in the view a make something like this:
bandList = Band.objects.all()
To retrieve all the bands but I can't figure out how to get all the Albums from a Band in the same view.
Any help will be appreciated. Thanks.
By default the related objects (through a ForeignKey on the other model) are accessible trough <modelname>_set zo in this case that is band.album_set (note this is a Manager attribute so you will probably use band.album_set.all() most of the time).
I personally prefer to give al my ForeignKey fields a related_name so I can name the attribute on the other model. The next example gives the Band the attribute band.albums.
class Band(models.Model):
# Band definition
class Album(models.Model):
band = models.ForeignKey(Band, related_name='albums')
# Rest of album definition
Could be great if you share your models definition. But I hope this helps you:
If you want to retrieve the Albums for a specific band:
band = Band.objects.get(...)
band_albums = Album.objects.filter(band=band)
That will return the albums for a band.
If you want retrive albums for all the bands:
bandList = Band.objects.all().select_related('album_set')
This will return the bans as before, but will cache the albums.

NHibernate AliasToBeanResultTransformer & Collections

I would like to return a DTO from my data layer which would also contain child collections...such as this:
Audio
- Title
- Description
- Filename
- Tags
- TagName
- Comments
- PersonName
- CommentText
Here is a basic query so far, but i'm not sure how to transform the child collections from my entity to the DTO.
var query = Session.CreateCriteria<Audio>("audio")
.SetProjection(
Projections.ProjectionList()
.Add(Projections.Property<Audio>(x => x.Title))
.Add(Projections.Property<Audio>(x => x.Description))
.Add(Projections.Property<Audio>(x => x.Filename))
).SetResultTransformer(new AliasToBeanResultTransformer(typeof(AudioDto)))
.List<AudioDto>();
Is this even possible, or is there another reccomended way of doing this?
UPDATE:
Just want to add a little more information about my scenario...I want to return a list of Audio items to the currently logged in user along with some associated entities such as tags, comments etc...these are fairly straight forward using MultiQuery / Future.
However, when displaying the audio items to the user, i also want to display 3 other options to the user:
Weather they have added this audio item to their list of favourites
Weather they have given this audio the 'thumbs up'
Weather the logged in user is 'Following' the owner of this audio
Favourites : Audio -> HasMany -> AudioUserFavourites
Thumbs Up : Audio -> HasManyToMany -> UserAccount
Following Owner : Audio -> References -> UserAccount ->
ManyToMany -> UserAccount
Hope this makes sense...if not i'll try and explain again...how can I eager load these extra details for each Audio entity returned...I need all this information in pages of 20 also.
I looked at Batch fetching, but this appears to fetch ALL thumbs ups for each Audio entity, rather than checking if only the logged in user has thumbed it.
Sorry for rambling :-)
Paul
If you want to fetch your Audio objects with both the Tags collection and Comments collections populated, have a look at Aydende Rahien's blog: http://ayende.com/blog/4367/eagerly-loading-entity-associations-efficiently-with-nhibernate.
You don't need to use DTOs for this; you can get back a list of Audio with its collections even if the collections are lazily loaded by default. You would create two future queries; the first will fetch Audio joined to Tags, and the second will fetch Audio joined to Comments. It works because by the time the second query result is being processed, the session cache already has the Audio objects in it; NHibernate grabs the Audio from the cache instead of rehydrating it, and then fills in the second collection.
You don't need to use future queries for this; it still works if you just execute the two queries sequentially, but using futures will result in just one round trip to the database, making it faster.