How to build One-To-Many relationships within JSON API - json

I`m very new to JS/APIs/JSON.
I`ve got an API I built using deployd, a great tool that allows to to quickly set up an API.
My API called "app" has two resources zips and people. Each entry/object in zips has only one property zipcode. Each people has the properties name and phonenumber.
I want to figure out a way to have people be associated with various zipcodes. Either one or many if necessary. This would, as I understand, involve adding a property to people such as assoczipcodes and using a relationship model to indicate with zipcodes are related.
I've done some research here about how a relationship is structured but I simply don't understand the syntax and format.
Q: What datatype is correct for associzipcodes?
Q: What do I enter into each assoczipcodes to indicate which zips are related?

Cristik's answer appears to be outdated. According to the current documentation, you'd want to nest the relationship like this:
{
"type": "people",
"id": "1",
"attributes": {
"name": "John Doe"
},
"relationships": {
"zipcodes": {
"links": {
"self": "http://myserver.com/people/1/zipcodes"
}
}
}
}

Based on the contents from the Resource Relationships section, the simplest approach would be to return an URL for the relationship, and have that URL return all information needed:
{
"type": "people",
"id": "1",
"name": "John Doe",
"links": {
"zipcodes": "http://myserver.com/people/1/zipcodes"
}
}

Related

FIWARE entity as a group of KPI attributes

Our system needs to return several KPIs grouped in different topics:
Census:
citizens (number of inhabitants)
citizens without any studies
...
Information desk
Phone response time
Mail response time
...
Tax
Online payments
Window payments
...
To my understanding, it would make sense to have an entity for each topic and each KPI being a KeyPerformanceIndicator attribute. eg: This could work similar to:
{
"description": "Census Information system",
"dataProvided": {
"entities": [
{
"idPattern": ".*"
}
],
"attrs":[ //THIS SEEMS AN INTERESTING APPROACH, BUT SADLY ALSO INVALID
{
"name": "citizens",
"type": "KeyPerformanceIndicator"
},
{
"name": "citizens_without_studies",
"type": "KeyPerformanceIndicator"
},
//...
]
},
"provider": {
"http": {
"url": "http://myhost/v2/census"
}
}
}
(TL;DR: "attrs" supports strings only, so can't return complex/data modeled types, like KPI)
Setting this happy idea aside, what it would be a good approach to solve this?
Must each KPI be an entity?
Is NGSI-LD what I'm looking for?
I think your case can be solved in NGIv2. Let my try to explain.
Must each KPI be an entity?
Yes. That's the usual way of modelling KPIs according to the KPIs datamodel. Each KPI is modeled as an entity of type KeyPerformanceIndicator.
Can KPIs be categorized?
Yes. You can use the category attribute to do that.
For instance, you can have an KPI "Online payments" of category "Tax Information" modeled this way:
{
"id": "OnlinePayments",
"type": "KeyPerformanceIndicator",
...
"category": ["taxInformation"],
...
}
Note that category is an array, so a given KPI could belong to more than one category (although in your use case it seems that each KPI belongs to exactly one category so you don't need this feature)
How can I get KPIs that belong to a given category?
You can use regular Orion Context Broker filtering features for that. For instance, to get all KPIs in category taxInformation you could use this key:
GET /v2/entitites?type=KeyPerformanceIndicator&q=category:taxInformation
or this expression in subscriptions:
{
"subject": {
"entities": [
{
"idPattern": ".*",
"type": "KeyPerformanceIndicator"
}
],
"condition": {
...
"expression": {
"q": "category:taxInformation"
}
}
},
...
}
If what you are trying to accomplish is to offer an NGSI interface for your KPI data, you can just create your own adaptor on top of your database that offers a REST interface compliant with NGSI-LD and such service can just return entities of type KeyPerformanceIndicator. Then, you can federate it to a Context Broker with a simple registration i.e. for entities of type KeyPerformanceIndicator. And that's all.
The usage of Linked Data would be recommendable as well, so I would go for NGSI-LD, as it has been officially endorsed by ETSI.

Is returning only IDs for a JSON API collection allowed?

So let's say I have a resources called articles. These have a numeric id and you can access them under something such as:
GET /articles/1 for a specific article.
And let's say that returns something like:
{
"data": {
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON:API paints my bikeshed!",
"body": "A bunch of text here"
}
}
}
Now my question is how to handle a request to GET /articles. I.e. how to deal with the request to the collection.
You see, accessing the body of the article is slow and painful. The last thing I want this REST API to do is actually try to get all that information. Yet as far as I can tell the JSON API schema seems to assume that you can always return full resources.
Is there any "allowed" way to return just the IDs (or partial attributes, like "title") under JSON API while actively not providing the ability to get the full resource?
Something like:
GET /articles returning:
{
"data": [
{
"type": "article_snubs",
"id": 1,
"attributes": {
"title": "JSON:API paints my bikeshed!"
}
}, {
"type": "article_snubs",
"id": 2,
"attributes": {
"title": "Some second thing here"
}
}
]
}
Maybe with links to the full articles?
Basically, is this at all possible while following JSON API or a REST standard? Because there is absolutely no way that GET /articles is ever going to be returning full resources due to the associate cost of getting the data, which I do not think is a rare situation to be in.
As far as I understand the JSON API specification there is no requirement that an API must return all fields (attributes and relationships) of a resource by default. The only MUST statement regarding fields inclusion that I'm aware of is related to Sparse Fieldsets (fields query param):
Sparse Fieldsets
[...]
If a client requests a restricted set of fields for a given resource type, an endpoint MUST NOT include additional fields in resource objects of that type in its response.
https://jsonapi.org/format/#fetching-sparse-fieldsets
Even so this is not forbidden by spec I would not recommend that approach. Returning only a subset of fields makes consuming your API much harder as you have to consult the documentation in order to get a list of all supported fields. It's much more within the meaning of the spec to let the client decide which information (and related resources) should be included.
The "attributes" object of a JSON-API doc does not need to be a complete representation:
attributes: an attributes object representing some of the resource’s data.
You can provide a "self" link to get the full representation, or perhaps even a "body" link to get just the body:
links: a links object containing links related to the resource.
E.g.
{
"data": [
{
"type": "articles_snubs",
"id": "1",
"attributes": {
"title": "JSON API paints my bikeshed!"
},
"links": {
"self": "/articles/1",
"body": "/articles/1/body"
}
},
{
"type": "article_snubs",
"id": "2",
"attributes": {
"title": "Some second thing here"
},
"links": {
"self": "/articles/2",
"body": "/articles/2/body"
}
}
]
}

Should the name of an array of objects in json be pluralized or not

What is the convention,should array of objects in json be pluralized or not
i.e
{
"releases": [
{
"id": "0b405ea7-8785-402f-bcf7-d55f5000dc3e",
"title": "Wintertunes"
},
{
"id": "7eb37a3a-646d-4501-a373-e9071186b88d",
"title": "Adventure Magic Supreme Journey Music"
}
],
}
versus
i.e
{
"release": [
{
"id": "0b405ea7-8785-402f-bcf7-d55f5000dc3e",
"title": "Wintertunes"
},
{
"id": "7eb37a3a-646d-4501-a373-e9071186b88d",
"title": "Adventure Magic Supreme Journey Music"
}
],
}
I believe Google JSON Style Guide is a good source for this kind of doubt.
Arrays usually contain multiple items, and a plural property name reflects this.
Also, the strongest argument for the plural form would be the direct object mapping you get from JSON.parse(). You probably want your Javascript code to deal with pluralized array objects.
Though, in case you have a million such entries - with no compression - that extra 's' will for sure produce some significant bloat :P
In the absence of any strong opinion decided to pluralize it

Freebase MQL to list out all commons types for a given word?

I'm trying to figure out how to write a MQL query to get a list of all the types associated to a given word.
For example I tried:
{
"id":null,
"name":null,
"name~=": "SOME_WORD",
"type":"/type/type",
"domain": {
"id": null,
"/freebase/domain_profile/category": {
"id": "/category/commons"
}
}
}​
I found this to list out all the Commons types or categories but haven't yet figured out how to narrow it down for a given input.
[{
"id": null,
"name": null,
"type": "/freebase/domain_profile",
"category": {
"id": "/category/commons"
}
}]​
There are a couple of different ways to do this with different tradeoffs for each.
Use the Search API with a query like this
https://www.googleapis.com/freebase/v1/search?indent=true&filter=%28all%20name{full}:%22uss%20constitution%22%29
You'll get back JSON results which look like this:
{
"status": "200 OK",
"result": [
{
"mid": "/m/07y14",
"name": "USS Constitution",
"notable": {
"name": "Ship",
"id": "/boats/ship"
},
"lang": "en",
"score": 1401.410400
},
...
You can make the matching more liberal by switching the "{full}" to "{phrase}" which will give you a substring match instead of an exact match.
Caveats:
- You'll only get a single "notable type" and it's fixed by Freebase's (unknown) algorithm
- I don't think there's a way to get both USS Constitution & U.S.S. Constitution results
- You can get a list of all types by adding &mql_output={"type":[]}, but then you lose the "notable" type. I don't think there's a way to get both in a single call.
Use MQL
This query returns the basic information that you want:
[{
"name~=":"uss constitution",
"type":[],
"/common/topic/notable_types" : []
}]​
Caveats:
It won't find "uss constitution" which is an alias rather than the primary name (there's a recipe in the MQL cookbook for that though)
It won't find "u.s.s. constitution"
The "notable_types" API is an MQL extension and MQL extensions aren't supported in the new Freebase API, only the legacy deprecated API
You're tied to whatever (unknown) algorithm Freebase used to compute "notability"
Depending on what you are trying to accomplish, you might need something more sophisticated than this (as well as a deeper understanding of what's in Freebase), but this should get you going with the basics.
Did you try:
[{
"name": "David Bowie",
"type": []
}]

Identifying Duplicates in CouchDB

I'm new to CouchDB and document-oriented databases in general.
I've been playing around with CouchDB, and was able to get familiar with creating documents (with perl) and using the Map/Reduce functions in Futon to query the data and create views.
One of the things I'm still trying to figure out is how to identify duplicate values across documents using Futon's Map/Reduce.
For example, if I have the following documents:
{
"_id": "123",
"name": "carl",
"timestamp": "2012-01-27T17:06:03Z"
}
{
"_id": "124",
"name": "carl",
"timestamp": "2012-01-27T17:07:03Z"
}
And I wanted to get a list of document id's that had duplicate "name" values, is this something I could do with the Futon Map/Reduce?
The result was hoping to achieve is as follows:
{
"name": "carl",
"dupes": [ "123", "124" ]
}
..or..
{
"carl": [ "123", "124" ]
}
.. which would be the value, and associated document ids which contain those duplicate values.
I've tried a few different things with Map/Reduce, but so far as I understand, the Map function works with data on a per-document basis, and the Reduce functions only allow you to work with the keys/values from a given document.
I know i could just pull the data I need with perl, work magic there, and get the result I want, but I'm trying to work only with CouchDB for now in order to better understand it's benefits / limitations.
Another way I'm thinking about doing this is to use a single document like an RDBMS table:
{
"_id": "names",
"rec1": {
"_id": "123",
"name": "carl",
"timestamp": "2012-01-27T17:06:03Z"
},
"rec2": {
"_id": "124",
"name": "carl",
"timestamp": "2012-01-27T17:07:03Z"
}
}
.. which should allow me to use the Map/Reduce functions in the way I originally thought. However I'm not sure if this is ideal.
I understand that my mind is still stuck in RDBMS land, so much of what I'm trying to do above may not be necessary. Any insight on this would be much appreciated.
Thanks!
Edit: Fixed JSON syntax in some of the examples.
If you merely want a list of unique values, that's pretty easy. If you wish to identify the duplicates, then it gets less easy.
In both cases, a map function like this should suffice:
function (doc) {
emit(doc.name);
}
For your reduce function, just enter _count.
Your view output will look like: (based on your 2 documents)
{
"rows": [
{ "key": "carl", "value": 2 }
]
}
From there, you will have a list of names as well as their frequency. You can take that list and filter it yourself, or you can take the "all couch" route and use a _list function to perform that final filtering.
function (head, req) {
var row, duplicates = [];
while (row = getRow()) {
if (row.value > 1) {
duplicates.push(row);
}
}
send(JSON.stringify(duplicates));
}
Read up about _list functions, they're pretty handy and versatile.