I'm trying to mock some data based on existing and working oData models. The Mock Server works, but I am struggling making the $expand to do it's job. I think it's mostly a matter of me not understanding where or how to store the JSON.
The metadata file is copied verbatim from the working service and contains all entities, entitysets, associations etcetera.
Here are some of the relevant bits. From Users entity:
<NavigationProperty Name="Dealers" Relationship="Y_DP_CORE_SRV.User_Dealer" FromRole="FromRole_User_Dealer" ToRole="ToRole_User_Dealer" />
The association:
<Association Name="User_Dealer" sap:content-version="1">
<End Type="Y_DP_CORE_SRV.User" Multiplicity="1" Role="FromRole_User_Dealer" />
<End Type="Y_DP_CORE_SRV.Dealer" Multiplicity="*" Role="ToRole_User_Dealer" />
<ReferentialConstraint>
<Principal Role="FromRole_User_Dealer">
<PropertyRef Name="Id" />
</Principal>
<Dependent Role="ToRole_User_Dealer">
<PropertyRef Name="Id" />
</Dependent>
</ReferentialConstraint>
</Association>
I can get Users('PRX-00015'). I cannot get Users('PRX-00015')/Dealers or Users('PRX-00015')?$expand=Dealers. There are no errors, but also no data.
Here's Users.JSON:
[{
"__metadata": {
"id": "http://localhost/sap/opu/odata/sap/Y_DP_CORE_SRV/Users('PRX-00015')",
"uri": "http://localhost/sap/opu/odata/sap/Y_DP_CORE_SRV/Users('PRX-00015')",
"type": "Y_DP_CORE_SRV.User"
},
"Id": "PRX-00015",
"FullName": "Jorg",
"Email": "",
"Telephone": "",
"InternalUser": false,
"Enabled": true,
"Dealers": {
"results": [{
"__metadata": {
"id": "http://localhost/sap/opu/odata/sap/Y_DP_CORE_SRV/Dealers('AA2002')",
"uri": "http://localhost/sap/opu/odata/sap/Y_DP_CORE_SRV/Dealers('AA2002')",
"type": "Y_DP_CORE_SRV.Dealer"
},
"Id": "AA2002"
}, {
"__metadata": {
"id": "http://localhost/sap/opu/odata/sap/Y_DP_CORE_SRV/Dealers('AA1046')",
"uri": "http://localhost/sap/opu/odata/sap/Y_DP_CORE_SRV/Dealers('AA1046')",
"type": "Y_DP_CORE_SRV.Dealer"
},
"Id": "AA1046"
}]
},
}]
I can also use the unexpanded version of Dealers and move the array into a Dealers.json file of it's own, in which case the line looks like
"Dealers": {
"__deferred": {
"uri": "http://localhost/sap/opu/odata/sap/Y_DP_CORE_SRV/Users('PRX-00015')/Dealers"
}
}
And Dealers.json
[{
"__metadata": {
"id": "http://localhost/sap/opu/odata/sap/Y_DP_CORE_SRV/Dealers('AA2002')",
"uri": "http://localhost/sap/opu/odata/sap/Y_DP_CORE_SRV/Dealers('AA2002')",
"type": "Y_DP_CORE_SRV.Dealer"
},
"Id": "AA2002"
}, {
"__metadata": {
"id": "http://localhost/sap/opu/odata/sap/Y_DP_CORE_SRV/Dealers('AA1046')",
"uri": "http://localhost/sap/opu/odata/sap/Y_DP_CORE_SRV/Dealers('AA1046')",
"type": "Y_DP_CORE_SRV.Dealer"
},
"Id": "AA1046"
}]
All of these result in an empty Dealers array (Dealers.length being 0). Anyone know how this works?
Normally project structure looks like this:
webapp/
- localService/
- mockdata/
- Y_DP_CORE_SRV.User
- Y_DP_CORE_SRV.Dealer.json
- metadata.json
But it doesn't really matter where your files are, it's matter how is your MockServer is implemented. The MockServer should mock real urls to your real server and return fake data from the files provided by you. Have you taken a look at this example already - https://sapui5.hana.ondemand.com/test-resources/sap/ui/templateapps/demokit/master-detail/webapp/localService/mockserver.js ?
Regarding expands. Normally, in xml views you can expand related entities with binding property by defining expand parameter. In javascript it works similar way. I can provide few examples when I get to my computer, but It's not really related to the MockServer since all expand parameters stay the same regardless it's mockdata or real data from the real backend...
UPDATE: here is an example how to expand models from the views and access properties:
<QuickView
binding="{path: 'to_Supplier', parameters: { expand: 'to_Address,to_PrimaryContactPerson' }}">
<QuickViewPage
title="{CompanyName}"
description="{to_PrimaryContactPerson/FormattedContactName}">
<QuickViewGroup>
<QuickViewGroupElement value="{to_Address/FormattedAddress}"/>
</QuickViewGroup>
</QuickViewPage>
</QuickView>
What code have you write for read OData?
OData requires urlParameters at the read operation:
oModel.read("/User", {
urlParameters:{
"$expand" : "Dealers"
},
success: function (oData) {
var oJson = new sap.ui.model.json.JSONModel();
oJson.setData(oData);
oVista.setModel(oJson);
}
});
You have to read Users Set and expand with the navigation property of dealers, as a result you must be get a tree with corresponding users dealers append from Dealers property of Users JSON object similar to:
User: {
property1 : value1,
... : ...,
Dealers : [
{ dealer1Property1 : dealer1Value1,
.... : .... },
{ dealer2Property1 : dealer2Value2,
.... : .... },
... ]
}
After that, the xml code of Skay must be successful.
Related
I am using Kafka Connect with JSONSchema and am in a situation where I need to convert the JSON schema manually (to "Schema") within a Kafka Connect plugin. I can successfully retrieve the JSON Schema from the Schema Registry and am successful converting with simple JSON Schemas but I am having difficulties with ones that are complex and have valid "$ref" tags referencing components within a single JSON Schema definition.
I have several questions:
The JsonConverter.java does not appear to handle "$ref". Am I correct, or does it handle it in another way elsewhere?
Does the Schema Registry handle the referencing of sub-definitions? If yes, is there code that shows how the dereferencing is handled?
Should the JSON Schema be resolved to a string without references (ie. inline the references) before submitting to the Schema Registry and thereby remove the "$ref" issue?
I am looking at the Kafka Source code module JsonConverter.java below:
https://github.com/apache/kafka/blob/trunk/connect/json/src/main/java/org/apache/kafka/connect/json/JsonConverter.java#L428
An example of the complex schema (taken from the JSON Schema site) is shown below (notice the "$ref": "#/$defs/veggie" tag the references a later sub-definition)
{
"$id": "https://example.com/arrays.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "A representation of a person, company, organization, or place",
"title": "complex-schema",
"type": "object",
"properties": {
"fruits": {
"type": "array",
"items": {
"type": "string"
}
},
"vegetables": {
"type": "array",
"items": { "$ref": "#/$defs/veggie" }
}
},
"$defs": {
"veggie": {
"type": "object",
"required": [ "veggieName", "veggieLike" ],
"properties": {
"veggieName": {
"type": "string",
"description": "The name of the vegetable."
},
"veggieLike": {
"type": "boolean",
"description": "Do I like this vegetable?"
}
}
}
}
}
Below is the actual schema returned from the Schema Registry after it the schema was successfully registered:
[
{
"subject": "complex-schema",
"version": 1,
"id": 1,
"schemaType": "JSON",
"schema": "{\"$id\":\"https://example.com/arrays.schema.json\",\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"description\":\"A representation of a person, company, organization, or place\",\"title\":\"complex-schema\",\"type\":\"object\",\"properties\":{\"fruits\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"vegetables\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/veggie\"}}},\"$defs\":{\"veggie\":{\"type\":\"object\",\"required\":[\"veggieName\",\"veggieLike\"],\"properties\":{\"veggieName\":{\"type\":\"string\",\"description\":\"The name of the vegetable.\"},\"veggieLike\":{\"type\":\"boolean\",\"description\":\"Do I like this vegetable?\"}}}}}"
}
]
The actual schema is embedded in the above returned string (the contents of the "schema" field) and contains the $ref references:
{\"$id\":\"https://example.com/arrays.schema.json\",\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"description\":\"A representation of a person, company, organization, or place\",\"title\":\"complex-schema\",\"type\":\"object\",\"properties\":{\"fruits\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"vegetables\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/veggie\"}}},\"$defs\":{\"veggie\":{\"type\":\"object\",\"required\":[\"veggieName\",\"veggieLike\"],\"properties\":{\"veggieName\":{\"type\":\"string\",\"description\":\"The name of the vegetable.\"},\"veggieLike\":{\"type\":\"boolean\",\"description\":\"Do I like this vegetable?\"}}}}}
Again, the JsonConverter in the Apache Kafka source code has no notion of JSONSchema, therefore, no, $ref doesn't work and it also doesn't integrate with the Registry.
You seem to be looking for the io.confluent.connect.json.JsonSchemaConverter class + logic
I'm developing an integration that will programmatically create product entries in Salesforce, and part of that process needs to be the addition of product images. I'm using the Connect API and am able to make a GET call to the right folder like this (I've scrambled the IDs and what not for this example):
https://example.salesforce.com/services/data/v52.0/connect/cms/delivery/channels/0591G0000000006/contents/query?folderId=9Pu1M000000fxUMSYI
That returns a payload like this:
{
"currentPageUrl": "/services/data/v52.0/connect/cms/delivery/channels/0ap1G0000000006/contents/query?page=0&pageSize=250",
"items": [
{
"contentKey": "MCZ2YVCGLNSBETNIG5P5QMIS4KNA",
"contentNodes": {
"source": {
"fileName": "PET Round.jpg",
"isExternal": false,
"mediaType": "Image",
"mimeType": "image/jpeg",
"nodeType": "MediaSource",
"referenceId": "05T0R000005MthL",
"resourceUrl": "/services/data/v52.0/connect/cms/delivery/channels/0ap1G0000000007/media/MCY2YVCGLNSBETNIG5P4QMIS4KNA/content",
"unauthenticatedUrl": "/cms/delivery/media/MCZ2YVCGLNSBETNIG5P4QMIS4KNA",
"url": "/cms/delivery/media/MCY2YVCGLNSBETNIG5P4QMIS4KNA"
},
"title": {
"nodeType": "NameField",
"value": "844333"
}
},
"contentUrlName": "844333",
"language": "en_US",
"managedContentId": "20T0R0000008U9qUAE",
"publishedDate": "2021-08-18T16:20:57.000Z",
"title": "844333",
"type": "cms_image",
"typeLabel": "Image",
"unauthenticatedUrl": "/cms/delivery/v52.0/0DB1G0000008tfOWAU/contents/20Y0R0000008y9qUAE?oid=00D0R000000OI7GUAW"
}
]
}
I am also able to retrieve images by contentKey with a GET call like this:
https://example.salesforce.com/services/data/v52.0/connect/cms/delivery/channels/0ap1G0000000007/media/MCZ2ZVCGLNSBETMIG5P4QMIS4KNA/content
Anyone know what the endpoint should look like and what parameters etc it should have? I'm having trouble finding anything for this specific scenario in the docs but surely there's a way.
Thanks!
I'm trying to validate a classic JSON schema (with Ajv and json-server) with required fields, but for a HTTP PATCH request.
It's okay for a POST because the data arrive in full and nothing should be ommited.
However, the required fields of the schema make problem when attempting to PATCH an existing resource.
Here's what I'm currently doing for a POST :
const schema = require('./movieSchema.json');
const validate = new Ajv().compile(schema);
// ...
movieValidation.post('/:id', function (req, res, next) {
const valid = validate(req.body);
if (!valid) {
const [err] = validate.errors;
let field = (err.keyword === 'required') ? err.params.missingProperty : err.dataPath;
return res.status(400).json({
errorMessage: `Erreur de type '${err.keyword}' sur le champs '${field}' : '${err.message}'`
});
}
next();
});
... but if i'm doing the same for a movieValidation.patch(...) and tries to send only this chunk of data :
{
"release_date": "2020-07-15",
"categories": [
"Action",
"Aventure",
"Science-Fiction",
"Thriller"
]
}
... it will fail the whole validation (whereas all the fields are okay and they validate the schema)
Here's my complete moviesSchema.json :
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"title": {
"title": "Titre",
"type": "string",
"description": "Titre complet du film"
},
"release_date": {
"title": "Date de sortie",
"description": "Date de sortie du film au cinéma",
"type": "string",
"format": "date",
"example": "2019-06-28"
},
"categories": {
"title": "Catégories",
"description": "Catégories du film",
"type": "array",
"items": {
"type": "string"
}
},
"description": {
"title": "Résumé",
"description": "Résumé du film",
"type": "string"
},
"poster": {
"title": "Affiche",
"description": "Affiche officielle du film",
"type": "string",
"pattern": "^https?:\/\/"
},
"backdrop": {
"title": "Fond",
"description": "Image de fond",
"type": "string",
"pattern": "^https?:\/\/"
}
},
"required": [
"title",
"release_date",
"categories",
"description"
],
"additionalProperties": false
}
For now, I did the trick using a different schema which is the same as the original one, but without the required clause at the end. But I don't like this solution as it's duplicating code unnecessarily (and it's not elegant at all).
Is there any clever solution/tool to achieve this properly?
Thanks
If you're using HTTP PATCH correctly, there's another way to deal with this problem.
The body of a PATCH request is supposed be a diff media type of some kind, not plain JSON. The diff media type defines a set of operations (add, remove, replace) to perform to transform the JSON. The diff is then applied to the original resource resulting in the new state of the resource. A couple of JSON diff media types are JSON Patch (more powerful) and JSON Merge Patch (more natural).
If you validate the request body for a PATCH, you aren't really validating your resource, you are validating the diff format. However, if you apply the patch to your resource first, then you can validate the result with the full schema (then persist the changes or 400 depending on the result).
Remember, in REST it's resources and representations that matter, not requests and responses.
It's not uncommon to have multiple schemas, one per payload you want to validate.
In your situation, it looks like you've done exactly the right thing.
You can de-duplicate your schemas using references ($ref), splitting your property subschemas into a separate file.
You end up with a schema which contains your model, and a schema for each representation of said model, but without duplication (where possible).
If you need more guidance on how exactly you go about this, please comment and I'll update the answer with more details.
Here is an example of how you could do what you want.
You will need to create multiple schema files, and reference the right schema when you need to validate POST or PATCH requests.
I've simplified the examples to only include "title".
In one schema, you have something like...
{
"$id": "https://example.com/object/movie",
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"movie": {
"properties": {
"title": {
"$ref": "#/definitions/title"
}
},
"additionalProperties": false
},
"title": {
"title": "Titre",
"type": "string",
"description": "Titre complet du film"
}
}
}
Then you would have one for POST and PATCH...
{
"$id": "https://example.com/movie/patch",
"$schema": "http://json-schema.org/draft-07/schema#",
"allOf": [{
"$ref": "/object/movie#/definitions/movie"
}],
}
{
"$id": "https://example.com/movie/post",
"$schema": "http://json-schema.org/draft-07/schema#",
"allOf": [{
"$ref": "/object/movie#/definitions/movie"
}],
"required": ["title"]
}
Change example.com to whatever domain you want to use for your ID.
You will then need to load in to the implementation all of your schemas.
Once loaded in, the references will work, as they are based on URI resolution, using $id for each schema resource.
Notice the $ref values in the POST and PATCH schemas do not start with a #, meaning the target is not THIS schema resource.
So I just used 2 working days trying to figure this out. We are automatic rendering process for maps. All the data is given in SQL base and my job is to write "wrapper" so we can implement this in our in-house framework. I managed all but one needed requests.
That request is POST featuretype since this is a way of creating a layer that can later be rendered.
I have all requests saved in postman for pre-testing on example data given by geoserver itself. I can't even get response with status code 201 and always get 500 internal server error. This status is described as possible syntax error in sytax. But I actually just copied and pasted exampled and used geoserver provided data.
This is the requst: http://127.0.0.1:8080/geoserver/rest/workspaces/tiger/datastores/nyc/featuretypes
and its body:
{
"name": "poi",
"nativeName": "poi",
"namespace": {
"name": "tiger",
"href": "http://localhost:8080/geoserver/rest/namespaces/tiger.json"
},
"title": "Manhattan (NY) points of interest",
"abstract": "Points of interest in New York, New York (on Manhattan). One of the attributes contains the name of a file with a picture of the point of interest.",
"keywords": {
"string": [
"poi",
"Manhattan",
"DS_poi",
"points_of_interest",
"sampleKeyword\\#language=ab\\;",
"area of effect\\#language=bg\\;\\#vocabulary=technical\\;",
"Привет\\#language=ru\\;\\#vocabulary=friendly\\;"
]
},
"metadataLinks": {
"metadataLink": [
{
"type": "text/plain",
"metadataType": "FGDC",
"content": "www.google.com"
}
]
},
"dataLinks": {
"org.geoserver.catalog.impl.DataLinkInfoImpl": [
{
"type": "text/plain",
"content": "http://www.google.com"
}
]
},
"nativeCRS": "GEOGCS[\"WGS 84\", \n DATUM[\"World Geodetic System 1984\", \n SPHEROID[\"WGS 84\", 6378137.0, 298.257223563, AUTHORITY[\"EPSG\",\"7030\"]], \n AUTHORITY[\"EPSG\",\"6326\"]], \n PRIMEM[\"Greenwich\", 0.0, AUTHORITY[\"EPSG\",\"8901\"]], \n UNIT[\"degree\", 0.017453292519943295], \n AXIS[\"Geodetic longitude\", EAST], \n AXIS[\"Geodetic latitude\", NORTH], \n AUTHORITY[\"EPSG\",\"4326\"]]",
"srs": "EPSG:4326",
"nativeBoundingBox": {
"minx": -74.0118315772888,
"maxx": -74.00153046439813,
"miny": 40.70754683896324,
"maxy": 40.719885123828675,
"crs": "EPSG:4326"
},
"latLonBoundingBox": {
"minx": -74.0118315772888,
"maxx": -74.00857344353275,
"miny": 40.70754683896324,
"maxy": 40.711945649065406,
"crs": "EPSG:4326"
},
"projectionPolicy": "REPROJECT_TO_DECLARED",
"enabled": true,
"metadata": {
"entry": [
{
"#key": "kml.regionateStrategy",
"$": "external-sorting"
},
{
"#key": "kml.regionateFeatureLimit",
"$": "15"
},
{
"#key": "cacheAgeMax",
"$": "3000"
},
{
"#key": "cachingEnabled",
"$": "true"
},
{
"#key": "kml.regionateAttribute",
"$": "NAME"
},
{
"#key": "indexingEnabled",
"$": "false"
},
{
"#key": "dirName",
"$": "DS_poi_poi"
}
]
},
"store": {
"#class": "dataStore",
"name": "tiger:nyc",
"href": "http://localhost:8080/geoserver/rest/workspaces/tiger/datastores/nyc.json"
},
"cqlFilter": "INCLUDE",
"maxFeatures": 100,
"numDecimals": 6,
"responseSRS": {
"string": [
4326
]
},
"overridingServiceSRS": true,
"skipNumberMatched": true,
"circularArcPresent": true,
"linearizationTolerance": 10,
"attributes": {
"attribute": [
{
"name": "the_geom",
"minOccurs": 0,
"maxOccurs": 1,
"nillable": true,
"binding": "com.vividsolutions.jts.geom.Point"
},
{},
{},
{}
]
}
}
So it is example case and I can't get any useful response from the server. I get the code 500 with body name (the first item in json). Similarly I get same code with body FeatureTypeInfo when trying with xml body(first tag).
I already tried the request in new instance of geoserver in Docker (changed the port) and still no success.
I check if datastore, workspace is available and that layer "poi" doesn't yet exists.
Here are also some logs of request (similar for xml body):
2018-08-03 07:35:02,198 ERROR [geoserver.rest] -
com.thoughtworks.xstream.mapper.CannotResolveClassException: name at
com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:79)
at .....
Does anyone know the solution to this and got it working. I am using GeoServer 2.13.1
So i was still looking for the answer and using this post (https://gis.stackexchange.com/questions/12970/create-a-layer-in-geoserver-using-rest) got to the right content to POST featureType and hence creating a layer in GeoServer.
The documentation is off in REST API docs.
Using above link I found out that when using JSON there is a missing insertion in JSON. For API to work here we need to add:
{featureType:
name: "...",
nativeName: "...",
.
.
.}
So that it doesn't start with "name" attribute but it is contained in "featureType".
I didn't try that for XML also but I guess it could be similar.
Hope this helps someone out there struggling like I did.
Blaz is correct here, you need an outer object of FeatureType and then an inner object with your config. So;
{
"featureType": {
"name": "layer",
"nativeName": "poi",
"your config": "stuff"
}
I find though that using a post request I get very little if any response and its not obvious if the layer creation worked. But you can call http://IP:8080/geoserver/rest/layers.json to check if your new layer is there.
It costs me a lot of time to create FeatureTypes using REST API. Use Json like this really works:
{
"featureType": {
"name": "layer",
"nativeName": "poi"
"otherProperties...":"values..."
}
And use Json below to create Workspace:
{
"workspace": {
"name": "test_workspace"
}
}
The REST API is out of date now. That's disappointing. Is there anyone knows how to get the lastest REST API document?
I have already created a function in IBM Cloud Functions, but how would I implement the parameters from user input?
What I'm trying to do is
For example: When a user types in "I need product" / "Buy product now" / Show me products. The product input is taken as a parameter and implements it into my Cloud Function, which displays all products that uses product as a keyword.
The response text would get info from the Cloud Function return output (which is a JSON array)
(res.body.items[?].name)
Example layout from IBM:
{
"context": {
"variable_name" : "variable_value"
},
"actions": [
{
"name":"getProducts",
"type":"client | server",
"parameters": {
"<parameter_name>":"<parameter_value>"
},
"result_variable": "<result_variable_name>",
"credentials": "<reference_to_credentials>"
}
],
"output": {
"text": "response text"
}
}
There is a full tutorial I wrote available in the IBM Cloud docs which features IBM Cloud Functions and a backend database. The code is provided on GitHub in this repository: https://github.com/IBM-Cloud/slack-chatbot-database-watson/.
Here is the relevant part from the workspace file that shows how a parameter could be passed into the function:
{
"type": "response_condition",
"title": null,
"output": {
"text": {
"values": []
}
},
"actions": [
{
"name": "_/slackdemo/fetchEventByShortname",
"type": "server",
"parameters": {
"eventname": [
"<? $eventName.substring(1,$eventName.length()-1) ?>"
]
},
"credentials": "$private.icfcreds",
"result_variable": "events"
}
],
"context": {
"private": {}
},
Later on, the result is presented, e.g., in this way:
"output": {
"text": {
"values": [
"ok. Here is what I got:\n ```<? $events['result'] ?>```",
"Data:\n ``` <? $events['data'] ?> ```"
],
"selection_policy": "sequential"
},
"deleted": "<? context.remove('eventDateBegin') ?><? context.remove('eventDateEnd') ?> <? context.remove('queryPredicate') ?>"
},
Some fancier formatting can be done, of course, by iterating over the result. Some tricks are here. The code also shows how to use a child node to process the result and to clear up context variables.
To obtain the parameter, in your case a product name or type, you would need to access either the input string and find the part after "product". Another way is to use the beta feature "contextual entity" which is designed for such cases.