API design for sub array of nested resources - json

I'm currently working on an API for an education app. There's a teacher resource and each teacher has a list of subjects that they teach. Currently, the GET teacher endpoint looks like this:
{
"first_name" : "Mister"
"last_name" : "Teacher"
"subjects" : [
{
"name" : "English",
"icons" : "/english-icon.png"
"id" : 1
},
{
"name" : "Math",
"icons" : "/math-icon.png"
"id" : 2
}
]
}
However, to me it doesn't make sense send the entire subject object when creating and updating the subjects, so the POST and PUT student endpoints accept parameters in the following form:
{
"first_name" : "Mister"
"last_name" : "Teacher"
"subject_ids": [1,2]
}
The inconsistency seems ugly, and it forces the client application to modify the format of an object before sending it to the server. Is there a more elegant solution?

First, you should include a link to each subject, not only the ID. This allows the client to navigate to a subject without having to build the URL from a pattern (which?) and the ID.
Second, your approach is fine if you think in think in representations. Both JSON structures are representations of the same resource. But they use different formats. In HTTP client and server would tell each other which format they send, request, or understand by using Content Negotiation.
If you do this, too, you are RESTful.

Related

JSON schema described by the values in a common model instead of the names defined in the schema

I am recommending to my client the use of a simplified data schema where the core document exchanged between parties via api has static mandatory information captured with identifiers, references, parties, dates, etc. and then has flexible objects within an array which can capture any data value which has taxonomy based metadata to describe what the value is.
The alternative method my client is considering, blows my mind. They are considering committing every piece of collected data to the schema with a self-describing value name.
We're talking about an insurance company - for liability and property cover types, there are over 300 questions between them. If this was a spreadsheet, that's a lot of columns. If a customer was only requesting property, then only 175 of those questions would be used and either the remainder are optional or null values.
What I'm proposing is, an example document received from a broker:
{
"characteristics" [
{
"category" : "business-activities",
"type" : "activities-hot-work",
"value" : "true"
},
{
"category" : "business-employees",
"type" : "employees-full-time",
"value" : "6"
}
]
}
Also, we could have another version of this document held at the API layer which uses the same categories and types but has the validation rules for the values received.
Example of validation version of the payload:
{
"characteristics" [
{
"category" : "business-activities",
"type" : "activities-hot-work",
"validation" : [
"value_type" : "boolean", "mandatory" : true
]
},
{
"category" : "business-employees",
"type" : "employees-full-time",
"validation" : [
"value_type" : "integer", "mandatory" : true
]
}
]
}
I would hope that using the two docs, the validation of resolving values to verification rules should be quite simple.
Is my logic making sense? What I want is to make the extending of what values are acceptable to receive to be a data management exercise instead of a new schema to be upgraded by all producers and consumers of a payload.
Additionally, I only want to receive the data I need for my request. I want the schema to be lightweight and flexible. I believe the schema does not need to be a flat version of an insurance product and every possible combination of questions.
I am thankful for your advice !

REST JSON API optional parameters design

Our goal is to develop API where you can POST /data/save/ that will accept some JSON data like below. The main requirement that JSON should contain one of the following attributes:
"attribute1", "attribute2", "attribute3". Namely when one attribute is exist another one should not exist.
{
"name": "test name",
"attribute1": [
"test1", "test2"
]
or
"attribute2": [
"test3", "test4"
]
or
"attribute3": true
}
The question is how to correctly design such API that it will be easy to use and not confused from the client side.
It would be good to know some best practices in such direction.
I would return a
400 Bad Request
The request could not be understood by the server due to malformed
syntax. The client SHOULD NOT repeat the request without
modifications.
and a phrase explaining that multiple attributes are not supported.
I agree such API is confusing for client side.
What's about creating different endpoints:
POST /data/save/attribute1 json_1
POST /data/save/attribute2 json_2
A custom media type should clarify how to use your API. It should specify what to include in your request.
Another solution might be, building the request like this:
{
"name": "test name",
"attr-key": "my-attribute1",
"values": ["test1", "test2"]
}

This Ember belongsTo relationship is working, but I can't see how

I've been developing an app for about a year now, so I started it mid-2014 and have been upgrading ember.js and ember-cli as things move forward on those projects. I'm at Ember 1.11 now.
EDIT: Application Adapter
var ApplicationAdapter = DS.RESTAdapter.extend( {
namespace: 'api',
host: null,
setHost: Ember.on('init', function() {
set(this, 'host', this.container._registry.resolve('config:environment').API_ENDPOINT);
})
});
export default ApplicationAdapter;
My JSON API returns a main projects object, along with other sideloaded objects (like projectStatus). What I can't understand is, since I don't have any adapters or serializers that specify this, how I'm it's able to use the returned JSON, because it looks like this:
{
"projects" : {
"id": 4462875
"projectName" : "New business from Acme",
"projectDescription" : "Just another great project",
"pmlinks" : [ 1, 2],
"statusLinks" : [ 1440 ],
"commentsLinks" : [ 39 ]
},
"projectResources" : [ {
"id" : 1,
"name" : "Wile E. Coyote"
}, {
"id" : 2,
"name" : "Roadrunner"
}],
"projectComments" : [ {
"id" : 39,
"projectComment" : "started the project",
} ],
"projectStatuses" : [ {
"id" : 1440,
"status" : "G",
"trending" : "N",
"comment" : null,
"lastModifiedDate" : "2015-07-17T13:46:11.037+0000",
"project" : 4462875
} ],
}
I can't find anything in the Ember docs that recommend this "*Links" format for the relationships, and in fact it suggests using something more like status_ids. But the example it shows doesn't use _ids so I'm even more confused.
Here's a snippet of my project model:
statusUpdates: DS.hasMany('projectStatus'),
projectComments: DS.hasMany('projectComment'),
projectResources: DS.hasMany('projectResource'),
What I'm trying to figure out is with my new belongsTo relationship to schedule, how should the JSON be formatted from the API? It seems to work if the project object has a property like this "scheduleLinks": [10] but not if it's like "schedule": 10 or "schedule_id": 10 and that seems to be what the documentation says should work.
EDIT:
Maybe it's because the other objects like projectComments are named the way my model expects, and they're all returned at the same time from one API, that it doesn't even matter what the properties in the projects object is? Is that only to look up relationships if they're not all sideloaded?
The sideloading definitely is the thing here. Because if I change "statusLinks" to "projectStatus" then, since I have that relationship established in the project model, it will try to hit the API for that, e.g. /api/projectstatuses/:id.
So what seems to be happening is that the relationship is being hooked up from the belongsTo side implicitly; if the data is sideloaded, I don't need any links or IDs on the main object.

Emitting JSON with optional arguments (Google API)

I'm writing a JSON emitter for a Google API. The API documentation says that some fields are "optional". How am I supposed to interpret that? I've looked at json.org's language specification and it doesn't say. Google's docs are not clear on the subject either.
For example, consider the "sellerData" field in the following:
{
"iss" : "1337133713371337",
"aud" : "Google"
"typ" : "google/payments/inapp/item/v1",
"exp" : "1309988959",
"iat" : "1409988959",
"request" :{
"name" : "Piece of Cake",
"description" : "Virtual chocolate cake to fill your virtual tummy",
"price" : "10.50",
"currencyCode" : "USD",
"sellerData" : "user_id:1224245,offer_code:3098576987,affiliate:aksdfbovu9j"
}
}
If I didn't have any "sellerData" to send, should I just send "sellerData": Null or just not put the field in at all? The former would make my emitter code much cleaner.
Optional fields can be completely omitted.
If you do not need "sellerData", do not add it to the JSON.
Once you set up a merchant sandbox account, the online documentation has a JWT generation tool that let's you experiment with setting various field values.
You can also double check your JWT creation with the JWT Decoder tool.

What is the correct way to use the fields request parameter when getting a list of StorageObjects from Google Cloud Storage?

I would like to do a lookup in the storage using the JSON API client library and only retrieve the name and generation of each object matching a specific prefix but I am having issues with the fields request parameter.
Executing the following returns the expected objects.
Storage.Objects.List listObjects = null;
listObjects.setVersions(true);
listObjects.setPrefix(myprefix);
URL being created for the request in com.google.api.client.http.HttpRequest is https://www.googleapis.com/storage/v1beta2/b/mybucketname/o?prefix=myprefix&versions=true
However, when I add
listObjects.setFields("name,generation");
with URL created being https://www.googleapis.com/storage/v1beta2/b/mybucketname/o?fields=name,generation&prefix=myprefix&versions=true the below is returned:
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"location" : "fields",
"locationType" : "parameter",
"message" : "Invalid field selection name",
"reason" : "invalidParameter"
} ],
"message" : "Invalid field selection name"
}
How am I supposed to be specifying the fields I want returned? Is the hierarchy of the fields I'm specifying not correct?
Thank you!
Ref:
Verified the composition of the URL based on this: https://developers.google.com/storage/docs/json_api/v1/how-tos/performance#partial
I think what you want is:
fields=items(generation,name)
or with the full URL:
https://www.googleapis.com/storage/v1beta2/b/mybucketname/o?fields=items(generation,name)&prefix=myprefix&versions=true
The APIs Explorer is a great tool for experimenting with request fields like this. It will generate the proper fields for you.