Best Practice Design typed JSON Objects - json

Currently we are designing a System that will send JSON Objects to registered consumers. The consumers will be able to register for different Object Types that they want to receive. Currently we are designing the JSON Objects that will be consumed by the registered consumers.
As we see there are two possible approaches to define typed JSON Objects.
A generic JSON Object that has some properties set or it has them not set:
{
"timestamp": 1589448935,
"customer_id": "123123123123",
"message": {
"title": "Desired Title",
"text": "The Text of the Message",
}
}
{
"timestamp": 1589448935,
"customer_id": "123123123123",
"message": {
"title": "Desired Title",
"text": "The Text of the Message",
"avatar": "http://avatar.io/avatar"
}
}
A Type field on each JSON Object that specifies which Type this object is from:
{
"timestamp": 1589448935,
"customer_id": "123123123123",
"type": "simple_message",
"message": {
"title": "Title",
"text": "Message",
}
}
{
"timestamp": 1589448935,
"customer_id": "123123123123",
"type": "avatar_message",
"message": {
"title": "Title",
"text": "Message",
"avatar": "http://www.avatar.io/avatar"
}
}
From our point of view a more generic approach would be easier to handle within our system, because we would not need to handle multiple types, we just can append a property or leave it away.
From point of view of a developer I could imagine that a type field could help the developer when handling such objects (f.e. mapping them to objects) or switch on the type field to execute some specific logic.
Finally, to my question - which style is the one to be preferred (best-practice) when we want to make the life for consumers as easy as possible and why? Is there a best-practice approach for typed json objects?

If you are set on a generic application/json response then I would go with your option #2.
That "type" doesn't hurt and can only help clarify what that response is.

Related

ADF pipeline get dynamic count of input parameters

I have a pipeline where I want to pass a JSON to from 3rd party application.
simple JSON Example, but the keys could be different for each call
{
"name": "Here is a name",
"guaid": "123456-123456-123456-111112",
"owner": "my.email#example.com",
"description": "here comes my description"
}
Passing the JSON is not the problem but I do not want to configure each parameter in the JSON as an pipeline parameter inside my ADF because it is not needed.
I do not modify the JSON inside my pipeline, I just have to surround it with some other parameters, so I need it as a whole.
I cloud of course define a parameter for each key in the JSON and concatenate it again but why do the effort if it is not needed.
I also can not modify how the JSON will be passed to my pipeline, so it is not possible to pass the whole JSON inside one parameter like this:
{
"inputParam": "{\"name\": \"Here is a name\",\"guaid\": \"123456-123456-123456-111112\",\"owner\": \"my.email#example.com\",\"description\":\"here comes my description\"}"
}
so is it possible to get all input without "knowing" it and use it in my activity?
My Pipeline is just simple, I only need a set variable and web activities, so I want to avoid a complex solution.
JSON Outbutt should look like this
{
"processingMode": "full",
"version": "1.0.0",
"content": [
{
"type": "Application",
"id": "akjhajf-ffsfsfs-sf-sf-sf",
"data": {
"name": "Here is a name",
"guaid": "123456-123456-123456-111112",
"owner": "my.email#example.com",
"description": "here comes my description"
}
}
]
}
I achieve this by adding this in a set variable like this with the not allowed method i mentioned above
{
"processingMode": "full",
"version": "1.0.0",
"content": [
{
"type": "Application",
"id": "#{guid()}",
"data": #{pipeline().parameters.inputParam}
}
]
}
I then just use this result JSON and call a external Webservice via Web activity

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"
}
}
]
}

How do we post messages to event grid topics?

I have created event grid topic in azure using event schema = "Event Grid Schema".
The next steps for me is trying to send messages to that event grid topic so the subscribers can do something when the message has been successfully received in event grid topic.
However, I had a problem when sending the message to event grid topic. It always reject my JSON request with error "Required property 'subject' was not set. even tough, I have explicitly set the subject in my JSON post body.
I have also add 'aeg-sas-key' value in header for authentication purposes.
Here is an example of my JSON format:
{
"id": "19291",
"subject": "myapp/vehicles/motorcycles",
"topic": "VehicleData",
"eventType": "statusupdated",
"eventTime": "2019-05-12T18:41:00.9584103Z",
"data":{
"firstName": "Jason",
"postalAddress": "xyz"
},
"dataVersion": "1.0",
"metadataVersion": "string"
}
and Here is the output:
{
"error": {
"code": "BadRequest",
"message": "Required property 'subject' was not set. Report '433759ee-6570-466e-ae12-a6dc5fccbfe1:5/14/2019 4:01:32 AM (UTC)' to our forums for assistance or raise a support ticket.",
"details": [
{
"code": "InputJsonInvalid",
"message": "Required property 'subject' was not set. Report '433759ee-6570-466e-ae12-a6dc5fccbfe1:5/14/2019 4:01:32 AM (UTC)' to our forums for assistance or raise a support ticket."
}
]
}
}
Any idea why it always ask for subject even tough I have provided the subject in my JSON?
Based on the docs:
Post to custom topic for Azure Event Grid
Azure Event Grid event schema
use the following payload:
[
{
"id": "19291",
"subject": "myapp/vehicles/motorcycles",
"topic": null,
"eventType": "statusupdated",
"eventTime": "2019-05-12T18:41:00.9584103Z",
"data": {
"firstName": "Jason",
"postalAddress": "xyz"
},
"dataVersion": "1.0",
"metadataVersion": null
}
]
If you created the topic using the Azure Portal, did you somewhere specify the inputSchemaMapping?
According to the specifications here: https://learn.microsoft.com/en-us/rest/api/eventgrid/topics/createorupdate
You need to specify a inputSchemaMapping when opting for the CustomEventSchema.

How do i document optional RESTful JSON API attributes?

I've been trying to figure out how to design the documentation for an API I'm building. I've been using Swagger (swagger.io) along with JSONSchema to help me structure the documentation, but I've run into a snag. Some of our object will have lots of what we call "metadata" attached to them, which is basically an arbitrary and variable dictionary of key/values. For example:
{
"id": "aabbbccdd",
"name": "Object 1",
"metadata": {
"attributeA": "This is a text attribute",
"attributeB": {
"key1": "complex attribute",
"key2": "complex attribute 2",
},
"attributeC": 1234
}
},
{
"id": "eeffffggghh",
"name": "Object 2",
"metadata": {
"attributeA": "This is a text attribute with a different value",
"attributeD": "Another text attribute",
"attributeE": True
}
}
So I could document the object representation by enumerating all the metadata attributes, but the list is long and will likely vary over time.
Is there another way to approach documenting this, or designing the API in a different way?

JSON Best Practice for Property Names

Is it "best practice" to use a GUID as a property name? (see sample JSON below)
{
"ErrorType": 0,
"I9e4f0477549111d997e0acd5cbb90d3f": {
"statusCode": "0",
"guid": "I9e4f0477549111d997e0acd5cbb90d3f",
"moreProperties": "more values"
},
"N51D209F0505711DEA52DFAD621371B7C": {
"statusCode": "0",
"guid": "N51D209F0505711DEA52DFAD621371B7C",
"moreProperties": "more values"
}
}
I would assume no because now isn't the whole "object" part of JSON gone? You no longer have access to the namespace because the property name is random. And serializing (using JSON.NET) is no longer a one-liner.
Furthermore there is repeated data. The GUID is the name of the property and within that property is another object with a property name of "guid". Data normalization is not being considered.
I'm not writing this JSON just consuming it. If I was writing this JSON I would rewrite it to this:
{
"ErrorType": 0,
"guids": [
{
"statusCode": "0",
"guid": "I9e4f0477549111d997e0acd5cbb90d3f",
"moreProperties": "more values"
},
{
"statusCode": "0",
"guid": "N51D209F0505711DEA52DFAD621371B7C",
"moreProperties": "more values"
}
]
}
Thoughts?
If you're searching for objects by GUID in Javascript, it's certainly better to use the GUID as a key, allowing you to write obj[someGuid].
Otherwise, it depends on the environment and usage; please provide more details.
As SLaks points out, it depends on how you are trying to use the JSON. Given:
allObjects = {
"ErrorType": 0,
"I9e4f0477549111d997e0acd5cbb90d3f": {
"statusCode": "0",
"guid": "I9e4f0477549111d997e0acd5cbb90d3f",
"moreProperties": "more values"
},
"N51D209F0505711DEA52DFAD621371B7C": {
"statusCode": "0",
"guid": "N51D209F0505711DEA52DFAD621371B7C",
"moreProperties": "more values"
}
}
myguid = "N51D209F0505711DEA52DFAD621371B7C";
you can simply access the data like allObjects[myguid]["moreProperties"]. If you generated the JSON as you suggest (without the guid as a key) and had to pull a value pertaining to a particular guid you would be forced to iterate over the array items and check for guid, like
for (var subObj in allObjects) {
if (subObj['guid'] = myguid) {
// you found it, store it and...
break;
}
}