JSON HAL - specify different formats for links - json

I know that you can indicate a "type" with a HAL link, like so:
{
_links: {
self: {
href: "http://example.site/api/orders/1",
hreflang: "en_US",
type: "application/hal+json"
}
}
}
But I'd like to explain the different types that are available at that href. For example, I want to state that both "application/hal+json" and "application/pdf" are valid representations Accept-ed by the resource URI.
Maybe something like:
{
_links: {
self: {
href: "http://example.site/api/orders/1",
hreflang: "en_US",
type: [
"application/hal+json",
"application/pdf"
]
}
}
}
or... ?
Is this possible? If so, how?

HAL uses the Link spec: https://datatracker.ietf.org/doc/html/rfc5988
This spec list only a single type per Link:
The "type" parameter, when present, is a hint indicating what the
media type of the result of dereferencing the link should be. Note
that this is only a hint; for example, it does not override the
Content-Type header of a HTTP response obtained by actually following
the link. There MUST NOT be more than one type parameter in a link-
value.

Related

JSON Schema / Formly dependent sub-schemas

This issue is a bit tricky to describe so bear with me and please ask questions if I am missing anything...
Say you have a json object that defines a list of features, each feature has a the same three properties but has a property that has an entirely different structure. For example:
{
features: [
{
id: "feature-a",
enabled: true,
configurationData: {
featureAConfigPropertyA: {
somePrperty: "whatever",
anotherProperty: true
},
featureAConfigPropertyB: "some string"
}
},
{
id: "feature-b",
enabled: true,
configurationData: {
featureBConfigArrayPropertyA: ["some string"],
featureBConfigPropertyB: [
{
"id": "some string",
"name": "some string",
"description": "some string",
"enabled": true
}
]
}
}
]
}
The actual structure of each feature is irrelevant. I am just trying to express this via json schema whereby the structure of configurationData for each feature is dependent on or dictated by the feature id value of its parent.
EDIT: I guess technically it doesnt need to be dependent on so long as either structure of configurationData is valid schema for that property on the feature schema itself. Also, the types in configurationData arent arbitrary, they would always be one of the two types for a given feature in this example.
This however needs to be structured in a way that can be expressed via Formly as I am using this to generate forms. In this case it would be an array of ObjectFieldTypes, one for feature a and one for feature b, which would enumerate the three properties and provide Input field types, until it got to configurationData at which point it would use an ObjectFieldType again, which would now be different for each field type.
The issue here is that 1) I'm not sure how to express this in json schema and 2) I can't use things like patternProperties with formly because the properties have to be explicitly defined in the json schema in order for formly to render the field types for each property. Although patternProperties would technically be valid schema in this case, if the schema doesn't define those properties, then the model in the valueChanges observable on the FormGroup just excludes them entirely. So I would end up with:
{
features:[
{
id: "feature-a",
enabled: true,
configurationData: { }
},
{
id: "feature-b",
enabled: true,
configurationData: { }
}
]
}
I have tried the if then else construct, but I cant tell if the schema is wrong or if formly just doesn't support this. I made a stack blitz for this below:
https://stackblitz.com/edit/angular-g45ydm?file=src%2Fassets%2Fjson-schema%2Fif_then.json

Monaco editor default json uri schema

I'm using monaco editor to edit JSON and I would like to set a custom diagnostic option.
I'm trying that https://microsoft.github.io/monaco-editor/playground.html#extending-language-services-configure-json-defaults
// Configures two JSON schemas, with references.
var jsonCode = [
'{',
' "p1": "v3",',
' "p2": false',
"}"
].join('\n');
var modelUri = monaco.Uri.parse("a://b/foo.json"); // a made up unique URI for our model
var model = monaco.editor.createModel(jsonCode, "json", modelUri);
// configure the JSON language support with schemas and schema associations
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
validate: true,
schemas: [{
uri: "http://myserver/foo-schema.json", // id of the first schema
fileMatch: [modelUri.toString()], // associate with our model
schema: {
type: "object",
properties: {
p1: {
enum: ["v1", "v2"]
},
p2: {
$ref: "http://myserver/bar-schema.json" // reference the second schema
}
}
}
}, {
uri: "http://myserver/bar-schema.json", // id of the second schema
schema: {
type: "object",
properties: {
q1: {
enum: ["x1", "x2"]
}
}
}
}]
});
monaco.editor.create(document.getElementById("container"), {
model: model
});
Where does uri: "http://myserver/foo-schema.json" come from ? I just want to use default JSON schema. Not my own.
Setting uri like this works :
uri: "http://localhost:4200/assets/monaco-editor/min/vs/language/json/jsonMode.js",
But is there a clean way to set this value ? Maybe uri value for JSON is available somewhere ? I searched through monaco.languages.json.jsonDefaults but I did not find anything.
"http://myserver/foo-schema.json" is an arbitrary value-- you can make it anything you want. It only matters if you are also using enableSchemaRequest-- in which case it should point to the location that you want the schema to be fetched from-- but you're not doing that, so that doesn't matter. In fact, everything related to this URI is irrelevant to what you are trying to do, if I'm understanding your intent correctly.
When you say "I just want to use default JSON Schema, Not my own", I think what you mean to say is that you just want to ensure that it is valid JSON, right? Because, there is no such thing as "default JSON Schema"-- by definition, it is defined by you-- but there is such a thing as a formal definition of what JSON is (JSON Schema, on the other hand, assumes that you are already starting with valid JSON, and allows you to then define a schema that your (valid) JSON must conform to).
Assuming you just want to ensure it is valid JSON (but you don't care that the json conform to some custom schema), setting the language to 'json' is all you need to do and your code can be as simple as:
var myBadJSONText = '{this is not : "JSON"}'
monaco.editor.create(document.getElementById('container'), {
language: 'json',
value: myBadJSONText
});
which running in the Monaco playground gives you:

(electron-store) How can I use "patternProperties" when define schema

I am using library for my electron app called electron-store
It has a feature to validate config data.
I want the value to be stored in config file is a string. I can achive that by define schema like this:
const schema = {
1: {
type: 'string',
},
2: {
type: 'string',
},
3: {
type: 'string',
},
4: {
type: 'string',
},
};
const store = new Store({schema});
The data in my config.json file:
{
"1": "lorem epsum...",
"2": "epsum lorem...",
"3": "epsum epsum...",
"4": "lorem lorem..."
}
The problem is I have hundreds line of datas like that, so it would be great if I could just define:
const schema = {
[any_key_name]: {
type: 'string',
},
};
I think I can use "patternProperties" when defining schema to achive it but I don't know how. help me please.
It looks like you cannot do this with electron-store as you want.
The docs say the following:
You should define your schema as an object where each key is the name
of your data's property and each value is a JSON schema used to
validate that property.
https://github.com/sindresorhus/electron-store#schema
This means that the root "schema" is not a JSON Schema. Only the value of each KEY is a JSON Schema.
If you want to use dynamic names, I think you would need to nest it under a specific key name, and validate that as a single object, although this is probably not what you really want to do with a store.
Sorry, I'm not familiar with electron-store specifically.
If you COULD provide a full JSON Schema for the whole store...
You can use patternProperties.
If you don't need to check the key follows any specific regex, you can use additionalProperties, which would then cover all properties not checked by properties (if present).
LEt's look at the specification: https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.6
The value of "additionalProperties" MUST be a valid JSON Schema.
This keyword determines how child instances validate for objects,
and does not directly validate the immediate instance itself.
Validation with "additionalProperties" applies only to the child
values of instance names that do not match any names in "properties",
and do not match any regular expression in "patternProperties".
As a pure JSON Schema, you'd be looking at...
{
"additionalProperties": {
"type": "string"
}
}
You can easily test this using https://jsonschema.dev (link has an example for you)

consuming json with digit variable names in typescript

I'm consuming the JSON from swagger, and when I get to the responses I get a bunch of variables that are the response codes, aka numbers. The relevant section of the JSON is below.
"responses": {
"200": {
"description": "OK"
},
"404": {
"description": "not found"
},
"503": {
"description": "Problem with external dependency"
}
}
How do I deserialize this into a Typescript object or should I use a service to consume this and process it before handing something more manageable to Typescript? My current idea is to handle it in javascript, then spit something back that is easier to consume in typescript; but before diving down that rabbit hole (ok, not quite that bad, I can see the bottom) I figured that I'd see if there is a better solution.
TypeScript only exists at compile-time. At run-time everything is plain old JavaScript.
As (de)serialization happens at run-time you would be deserializing it in to a JavaScript object, but I assume you mean "Is it possible to create a TypeScript type definition that describes this incoming object?".
Also, the property names aren't numbers, they're strings that happen to contain numbers. This is an important distinction when creating a type definition as a string and a number are two different types.
The first step is to define the Response objects:
interface IResponse {
description: string;
}
Then, there are two approaches that can be taken for defining the Responses object. The first can be used if the property names are known in advance, the second can be used in a more generic fashion to support any property names of a given type.
Known Names
interface IKnownResponses {
"200": IResponse;
"300"?: IResponse;
"400": IResponse;
}
This defines an interface that must have properties called "200" and "400", and can optionally have a property called "300".
"300" is optional (search for the "Optional Properties" title) as it's property definition has a ? in it.
Dynamic Names
interface IDynamicResponses {
[responseCode: string]: IResponse;
}
This interface says that any string can be used as a key/property name, but that the property must contain an IResponse.
This is an indexer definition (look for the section titled "Indexable Types").
Example
These approaches can be seen working in the following example code:
interface IResponse {
description: string;
}
interface IKnownResponses {
"200": IResponse;
"300"?: IResponse;
"400": IResponse;
}
interface IDynamicResponses {
[responseCode: string]: IResponse;
}
let knownResponses: IKnownResponses = {
"200": {
description: "foo"
},
"400": {
description: "bar"
}
};
let dynamicResponses: IDynamicResponses = {
"200": {
description: "foo"
},
"400": {
description: "bar"
},
"401": {
description: "baz"
}
};
console.log(staticResponses["200"].description);
console.log(knownResponses["401"].description);
https://jsfiddle.net/L8dpomL8/3/
Unfortunately JSFiddle isn't a very good TypeScript IDE so it's hard to show the type information being used, but if you take this code and put it in your preferred IDE you should be able to experiment with it and figure out where the typings help you, and where they fail.

Emit couchbase data

I would like to emit couchbase data in the following format :
rows: [
{
id: "UniqueID",
key: "UniqueKey",
doc: {
meta: {
id: "UniqueID"
},
json: {
//ACTUAL DOCUMENT HERE
}
}
}
,
.... Second document and so on
When I try to create a view :
function (doc, meta) {
emit(meta.id, doc);
}
It emits the data in the following fashion :
total_rows: 55, -- DO NOT NEED THIS
rows: [
{
id: "UniqueID",
key: "UniqueKey",
value: {
//ACTUAL DOCUMENT HERE
}
},
.... Second document and so on
How do I modify the view to output the exact same schema as mentioned above ?
You don't. View response follows a defined format that tools like the SDKs rely on for parsing.
Also it is generally not a good idea to emit the whole document: since the value of the view get stored in the secondary index, you are basically duplicating all your data in the key/value store and the view index...
View responses always include the document ID for a particular row, so you can always get the document by performing a key/value GET. The SDKs can also abstract that away in their API (eg. in Java there's a document() method on each row object).