Should I include URLs or Ids of resources in REST API response? - rest

I am designing a REST API. There's an entity Organization which may have a parent organization and multiple child organizations.
Let's say a user does request GET /organizations/1234.
What should I respond with?
I can use URLs to these other organizations.
{
"data": {
"name": "Microsoft",
"parent_organization": "http://api.myapi.asdfghj/organizations/1220",
"child_organizations": [
"http://api.myapi.asdfghj/organizations/1236",
"http://api.myapi.asdfghj/organizations/1214"
]
}
}
or I can use their ids
{
"data": {
"name": "Microsoft",
"parent_organization": 1220,
"child_organizations": [
1236,
1214
]
}
}
Which one is better?
If it's the one with full URLs, how do I do document that in swagger? Do I just set that as a string, something like the following?
definitions:
Organization:
type: object
properties:
data:
type: object
properties:
name:
type: string
parent_organization:
type: string
format: url
child_organizations:
type: array
items:
type: string
format: url
What about POST /organizations for creating a new user? Should the user specify parent and children as urls too?

I suggest you use urls rather than some ids. The advantage of having actual urls is that you can change them dynamically without worrying about the clients who depend on some base urls and then have to compute the actual urls from ids, etc.
For documentation purpose you can treat urls as strings and explain them like other params.

Related

OpenAPI - different schema per operation on same resource

I'm using OpenAPI 3.0 to describe an API where each resource has a subtly different schema based on its operation. Essentially certain properties are editable and/or required based on whether it's a POST or PUT request.
Is there a better way to do this other than specify a schema for each operation like this? (where field2 is readOnly on the PUT)
Ideally, I'd like to specify the schema (i.e. all the properties) in one place and then override some properties (e.g. readOnly) on each operation.
{
"paths":{
"/users":{
"put":{
"responses":{
"200":{
"$ref":"#/components/schemas/users_put"
}
}
},
"post":{
"responses":{
"200":{
"$ref":"#/components/schemas/users_post"
}
}
}
}
},
"components":{
"schemas":{
"users_post":{
"properties":{
"field1":{
"readOnly":true,
"type":"integer"
},
"field2":{
"type":"string"
}
}
},
"users_put":{
"properties":{
"field1":{
"readOnly":true,
"type":"integer"
},
"field2":{
"type":"string",
"readOnly":true
}
}
}
}
}
}
As far as I know, there is no override mechanism in openapi/swagger models.
But composition (extending) models is available.
Since in your example you need to update only readOnly directives (which means you mark properties that's available only in responses) try other approach when you describe requests and responses separately.
Such in your example the response for put and post methods would be the same (because they both have field1 and field2), and only put will have request (because in post all fields is readOnly):
(I use yaml for brevity, but it's easy convert to json back)
paths:
"/users":
put:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/users_put_request'
responses:
'200':
"$ref": "#/components/schemas/users_response"
post:
responses:
'200':
"$ref": "#/components/schemas/users_response"
components:
schemas:
users_response:
field1:
type: integer
field2:
type: integer
users_put_request:
field2:
type: string
Probably with this approach the different parts of models is describe explicitly.

RESTful API design advice on getting all A associated with B

I'm trying to design a RESTful API as a side project.
I am also using MongoDB as database
(I'm new to NoSQL design, so I need help, If I have misunderstanding in how documents should be designed).
I have example entities as following:
Event {
id: string
name: string
date: date
location: location
subgroups: group[]
}
Group {
id: string
owners: user[]
members: user[]
parentEvent: event
posts: post[]
}
User {
id: string
Name: string
attendingGroups: group[]
owningGroups: group[]
}
post {
id: string
parentgroup: Group
}
location {
id: string
city: string
}
For above example,
Should I have a designated get call for having all groups associated with the user?
or should I get a user and get the associated groups from the user retrieved?
Depends how you design it. You can embed resources in other resources to save you from N+1 select problem, nothing is against with that.
Hal+json format is the format you should be embedding resources.
In REST you can even have ?_embed=groups parameter to embed or not.
Embedding or not embedding is up to your applications needs, not embedding way = you should design a filter like /groups?user=eralpb to get the groups. Or sub-resources work as well like /users/eralpb/groups should only return my groups.

Api response structure with configurable columns definitions

I am building an application for a student application system which allows multiple organisations to provide an online application form to its students to apply for courses.
For each application, it will have ID, StudentName, CourseName. However some universities require SecondaryExamMark and some requires Reference name and reference contact no.
I am making an API call (/application/list?pageNo=1&rowsPerPage=20&orgId=1)
and returns all application data with common information plus the extra requirements based on the organisation id provided
I defined an application model that includes all common properties plus a subset of properties all organisations requested and store them in a single database table with a few nullable fields for different organisation.
In terms of the Api response structure, which of the following is more appropriate?
{
ID: 1,
StudentName: 'A B',
CourseName: 'B C',
ReferenceName: null,
ReferenceContact: null,
SecondarySchoolMark: '80'
}
OR
{
headers: [
{
Title: "ID",
Type: "text"
},
{
Title: "StudentName",
Type: "text"
},
{
Title: "CourseName",
Type: "text"
},
{
Title: "SecondarySchoolMark",
Type: "text"
}
],
application: [
{
Title: "ID",
Value: "12345"
},
{
Title: "StudentName",
Value: "A B"
},
{
Title: "CourseName",
Value: 'B C'
}
{
Title: 'SecondarySchoolMark',
Value: '80'
}
]
}
The first approach seems to be a general Api structure which returns an object that describes an application. However the second approach allows the Api to decide which columns should be rendered, and UI would only have to treat the response as display fields.
IMO, i would prefer the first approach because in order to make the API integrate-able with other clients, the API should provide resource based responses. And showing or hiding the columns (whether based on another Api call to /getdisplaycolumns?orgId=1 or just treat null columns as hidden is UI's responsibility)
Edit 1: not necessarily returning the null properties from the approach one as Json serializer allows to ignore null properties)
I agree, settling on a model (resource) that has a couple of nullable properties that the client can ignore sounds like a more robust design (strongly typed properties!) than deserializing whatever the second model is into a Dictionary of sorts and working with that.

Rest API get resource id by field

What is a correct rest way of getting a resource ID by a field, for example a name. Take a look at the following operations:
GET /users/mike-thomas
GET /users/rick-astley
I don't want to use these operations at my API end, instead I want to write an API operation that will get me the ID when submitting a field (name in the case of users) for example:
GET /users/id-by-field
Submitted data:
{
"fullName": "Mike Thomas"
}
Return data:
{
"data": {
"id": "123456789012345678901234"
}
}
What you want is known as an algorithmic URL where the parameters for the algorithm are passed as URL parameters:
GET /users?name="Mike Thomas"
Advantages are that you are using the "root" resource (users) and the search parameters are easily extended without having to change anything in the routing. For example:
GET /users?text="Mike"&year=1962&gender=M
where text would be searched for in more than just the name.
The resultant data would be a list of users and could return more than the identification of those users. Unless fullName uniquely identifies users, that is what you need to allow for anyway. And of course the list could contain a single user if the parameters uniquely identified that user.
{
users: [
{
id: "123456789012345678901234",
fullName: "Mike Thomas",
dateJoined: 19620228
}
, {
id: "234567890123456789012345"
fullName: "Rick Astley",
dateJoined: 19620227
}
]
}

In WCF Data Services, can I enclose a list of references to another entity while creating a new object?

I have a table Article, a table Tag and a joint table to associate a tag to an article.
While creating a new Article, by sending a POST request to /Service.svc/Articles, is it possible to enclose in the JSON object a list of Tag ids to be associated?
Something like:
{
title: "My article title",
text: "The content:",
Tags: [ { id: 1 }, { id: 2 }, { id: 3 } ]
}
If not can I send the list of tags in one request? For example:
/Service.svc/Articles(1)/Tags
[ { id: 1 }, { id: 2 }, { id: 3 } ]
Or do I have to make as many requests as they are tags?
Thank you very much in advance.
You can modify just the links by POST/PUT/DELETE to the $links URL as described here: http://www.odata.org/developers/protocols/operations#CreatingLinksbetweenEntries
The samples there use ATOM/XML, but the respective JSON format is also possible.
To send multiple operations to the server in one request (to save the roundtrips) you can create a batch request as described here:
http://www.odata.org/developers/protocols/batch