Express that, for a given property value, a property with the same name should exist using json schema? - validation

I'm trying to validate json files which have an element that has a property which contains a value that should exist in another part of the json. I'm using jsonschema Draft 07.
This is a simple little example that shows the scenario I'm trying to validate in my data.
{
"objects": {
"object1": {
"colorKey": "orange"
}
},
"colors": {
"orange": {
"red": "FF",
"green": "AF",
"blue": "00"
}
}
}
How can I validate that the 'value' of colorKey (in this case 'orange') actually exists as a property of the 'colors' object? The data isn't stored in arrays, just defined properties.

For official JSON Schema...
You cannot check that a key in the data is the same as a value of the data.
You cannot extract the value of data from your JSON instance to use in your JSON Schema.
That being said, ajv, the most popular validator, implements some unofficial extensions. One of which is $data.
Example taken from: https://github.com/epoberezkin/ajv#data-reference
var ajv = new Ajv({$data: true});
var schema = {
"properties": {
"smaller": {
"type": "number",
"maximum": { "$data": "1/larger" }
},
"larger": { "type": "number" }
}
};
var validData = {
smaller: 5,
larger: 7
};
ajv.validate(schema, validData); // true
This would not work for anyone else using your schemas.

Related

How to return complex object as scalar type in GraphQL?

Let's imagine we have GraphQL API that can return an object Entity with Id and Name properties and I requested Name only:
query {
entities {
name
}
}
And it returns
{
"data": {
"entities": [
{
"name": "Name1"
},
{
"name": "Name2"
}
]
}
}
But what if I want to have only the name of entities as a scalar type? In other words, I want to have something like:
{
"data": {
"entities": [
"Name1",
"Name2"
]
}
}
Is it possible to have such result without changes on the GraphQL API side? Aliases, Fragments, etc. GraphQL has a lot of built-in query capabilities, but none of the known me can return complex objects as scalar type.
what you're asking for is almost impossible if you don't want to change the type definition for Entities.
This: 👇🏽
Entity: id: int! name: String
entities(): [Entity]
returns an array of objects with keys name and id.
To achieve what you're asking you either change Entity to be just a string or have your client reduce that object to an array of just Entity names when they receive it.
They could do something like this:
const data = {
entities: [
{
name: 'Name1',
},
{
name: 'Name2',
},
],
};
const entityNames = data.entities.reduce(
(acc, curr) => [...acc, curr.name],
[]
);
console.log(entityNames);

How to adapt query to API?

I'm trying to wrap my head around GraphQL.
Right now I'm just playing with the public API of Artsy (an art website, playground at https://metaphysics-production.artsy.net). What I want to achieve is following:
I want to get all node types entities without declaring them by hand (is there a shortcut for this)?
I want every node with a field type from which I can read the type, without parsing through imageUrl etc. to fint that out.
What I constructed as of right now is this:
{
search(query: "Berlin", first: 100, page: 1, entities: [ARTIST, ARTWORK, ARTICLE]) {
edges {
node {
displayLabel
imageUrl
href
}
}
}}
Very primitive I guess. Can you guys help me?
TL;DR:
1) There is no shortcut, it's not something GraphQL offers out of the box. Nor is it something I was able to find via their Schema.
2) Their returned node of type Searchable does not contain a property for type that you're looking for. But you can access it via the ... on SearchableItem (union) syntax.
Explanation:
For question 1):
Looking at their schema, you can see that their search query has the following type details:
search(
query: String!
entities: [SearchEntity]
mode: SearchMode
aggregations: [SearchAggregation]
page: Int
after: String
first: Int
before: String
last: Int
): SearchableConnection
The query accepts an entities property of type SearchEntity which looks like this:
enum SearchEntity {
ARTIST
ARTWORK
ARTICLE
CITY
COLLECTION
FAIR
FEATURE
GALLERY
GENE
INSTITUTION
PROFILE
SALE
SHOW
TAG
}
Depending on what your usecase is, if you're constructing this query via some code, then you can find out which SearchEntity values they have:
{
__type(name: "SearchEntity") {
name
enumValues {
name
}
}
}
Which returns:
{
"data": {
"__type": {
"name": "SearchEntity",
"enumValues": [
{
"name": "ARTIST"
},
{
"name": "ARTWORK"
},
...
}
}
}
then store them in an array, omit the quotation marks from the enum and pass the array back to the original query directly as an argument.
Something along the lines of this:
query search($entities: [SearchEntity]) {
search(query: "Berlin", first: 100, page: 1, entities: $entities) {
edges {
node {
displayLabel
imageUrl
href
}
}
}
}
and in your query variables section, you just need to add:
{
"entities": [ARTIST, ARTWORK, ...]
}
As for question 2)
The query itself returns a SearchableConnection object.
type SearchableConnection {
pageInfo: PageInfo!
edges: [SearchableEdge]
pageCursors: PageCursors
totalCount: Int
aggregations: [SearchAggregationResults]
}
Digging deeper, we can see that they have edges, of type SearchableEdge - which is what you're querying.
type SearchableEdge {
node: Searchable
cursor: String!
}
and finally, node of type Searchable which contains the data you're trying to access.
Now, the type Searchable doesn't contain type:
type Searchable {
displayLabel: String
imageUrl: String
href: String
}
But, if you look at where that Searchable type is implemented, you can see SearchableItem - which contains the property of displayType - which doesn't actually exist in Searchable.
You can access the property of SearchableItem and get the displayType, like so:
{
search(query: "Berlin", first: 100, page: 1, entities: [ARTIST, ARTWORK, ARTICLE]) {
edges {
node {
displayLabel
imageUrl
href
... on SearchableItem {
displayType
}
}
}
}
}
and your result will look like this:
{
"data": {
"search": {
"edges": [
{
"node": {
"displayLabel": "Boris Berlin",
"imageUrl": "https://d32dm0rphc51dk.cloudfront.net/CRxSPNyhHKDIonwLKIVmIA/square.jpg",
"href": "/artist/boris-berlin",
"displayType": "Artist"
}
},
...

In FormFlow, How do i get the form values after form is done?

I have a complete Form that has different fields. Name, phone and so on.
Before complition, I would like to send the fields to a method then then sends an email. More specificly, I want to put the values on a dictionary and then pass it to the method.
Where are those values stored in the Form so I can get them?
This is my code
form.OnCompletion(processOrder);
var parameters = new Dictionary<string, string>
{
{ "tileid", "open" },
{ "src", "Facebook" },
{ "chid", "9" },
{ "apply-first-name", "xxx" },
{ "apply-last-name", "xxx" },
{ "apply-email", "xxx" }
};
sendAsync(parameters);
return form.Build();
I found the answer. All values are inside the ”state” objekt passed to the oncompletion method.

JqGrid custom formatter with custom parameter

I have a question about custom formatters.
What I try to achieve is a currencyFormatter just for the amount with Locale sent by the server, when locale is not define or supported fall back to British English.
Something like this:
function currencyFmatter(cellvalue, options, rowdata) {
return new Intl.NumberFormat([locale, "en-GB"], {minimumFractionDigits: 2, maximumFractionDigits: 2}).format(cellvalue);
}
My problem is how to pass my variable locale to the formatter, I’m pretty sure it has to be a way to do it but right now I don’t see it.
Thanks
It's an interesting question! There are many ways to implement your requirements.
1) you can extend your input data returned from the server with additional information which specify the locale of data. For example you can returns "de-DE:10.000,04" instead of "10.000,04" which represent 1000.04 formatted in German locale (where , will be used as the decimal separator and . used as the thousands separator). It allows you to use cellvalue.split(":") to get array ["de-DE", "10.000,04"] with the locale of the number and the number itself
function currencyFmatter(cellvalue, options, rowdata) {
var data;
if (typeof cellvalue === "string") {
data = cellvalue.cellvalue.split(":");
if (data.length === 2) {
return new Intl.NumberFormat([data[0], "en-GB"], {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}).format(data[1]);
}
}
return cellvalue;
}
Alternatively you can place the information about locale of the number in separate field (for example numLocale) of the input data and use something like rowdata.numLocale (or rowdata[12] depend on the input format of the JSON data) to access the locale.
2) It could be that all the data returned from the server will be in the same format. In the case it would be not the best way to prepend all numbers with the same prefix "de-DE:". What you can do for example is to extend the data returned from the server with additional field. For example you can use
{
"total": "12",
"page": "1",
"records": "12345",
"localOfNumbers": "de-DE",
"rows" : [
...
]
}
You can access the custom localOfNumbers field inside of beforeProcessing callback. It's very practical callback. It allows you to pre-process the data returned from the server before the data will be processed by jqGrid. I recommend you to read the answer and this one for more code example. What you can do for example is to save localOfNumbers value in some new option of jqGrid (see the answer for more details). Let us you want to have an option gridLocale for the goal. Then you can do something like the following:
beforeProcessing: function (data) {
if (typeof data.localOfNumbers === "string") {
$(this).jqGrid("setGridParam", {gridLocale: data.localOfNumbers});
}
}
To access the new gridLocale option you can use
function currencyFmatter(cellvalue, options, rowdata) {
var locale = $(this).jqGrid("getGridParam", "gridLocale"); // this.p.gridLocale
}
3) You can consider to save the information about the locale as column property instead of usage one common gridLocale grid option. To do this you can define the column in colModel like below
{ name: 'col2', width: 200, formatoptions: { colLocale: "en-IN" },
formatter: function (cellvalue, options, rowdata) {
// options.colModel.formatoptions.colLocale get you the value
}
One can set the property of formatoptions.colLocale inside of beforeProcessing too. You can use
{
"total": "12",
"page": "1",
"records": "12345",
"localOfColumns": {
"col2": "de-DE",
"col5": "en-IN"
},
"rows" : [
...
]
}
and
beforeProcessing: function (data) {
if ($.isPlainObject(data.localOfColumns)) {
if (typeof data.localOfColumns.col2 === "string") {
$(this).jqGrid("setColProp", "col2", {
formatoptions: { colLocale: data.localOfColumns.col2 }
});
}
if (typeof data.localOfColumns.col5 === "string") {
$(this).jqGrid("setColProp", "col5", {
formatoptions: { colLocale: data.localOfColumns.col5 }
});
}
}
}
I'm sure that one can suggest even more ways to implement your requirements.

How do I use this JSON to bind to a Kendo UI Grid

This JSON comes back from existing server and probably won't be changed - checks out as valid using JSONLint. Autobind does not work on this, and I can't get a grid to work with it:
[
{
"SearchResult":{
"assets":[
{
"agent":"6.1.0",
"id":1,
"model":"Gateway1",
"modelId":2,
"name":"Name",
"serialNumber":"Serial01",
},
{
"agent":"M2M",
"id":2,
"model":"Gateway1",
"modelId":3,
"name":"Name",
"serialNumber":"Serial02"
}
],
"searchCriteria":{
"paginationEnabled":false,
"rowsPerPage":-1,
"startRow":-1,
"totalAvailableRows":-1,
"alternateId":{
"#xsi.nil":"true"
},
"modelNumber":{
"#xsi.nil":"true"
},
"name":"*",
"serialNumber":{
"#xsi.nil":"true"
}
}
}
}
]
You should specify the array with data in the DataSource's schema.
Have in mind that the DataSource works with flat arrays. To display the "assets" try the following:
schema: {
data: function(rawData) {
return rawData[0].SearchResult.assets;
}
}
Here is a working example: http://jsbin.com/opocib/3/edit

Resources