I am using Spring cloud contract testing to try and contract test an API and can't figure out what is causing my test to fail.
I am using this groovy test file
package contracts.api.myClass;
import org.springframework.cloud.contract.spec.Contract
Contract.make {
request {
method 'GET'
url value(consumer(regex('path/myAPI/(\\w+)')), producer('/path/myAPI/id'))
headers {
contentType(applicationJson())
}
}
response {
status 200
headers {
contentType(applicationJson())
}
body("""
{
"requestId": "id",
"success": true,
"datalist": [
{
"id": 100,
"names": ["aaaa", "ffff"]
}
],
"failureInfo": {
"failureCode": 100,
"failureDesc": "failure"
}
}
""")
}
}
The API I am trying to test is generated using swagger code gen 2.0 from the following yaml
'/configurator/myAPI/{requestId}':
get:
operationId: myAPI
parameters:
- $ref: '#/parameters/GCCX-Request-Context'
- $ref: '#/parameters/GCCX-TransactionId'
- $ref: '#/parameters/X-B3-TraceId'
- $ref: '#/parameters/Accept-Language'
- $ref: '#/parameters/requestId'
tags:
- Configurator
consumes: [ ]
responses:
'200':
description: Return the response once operation is preformed in BO.
headers:
Content-Language:
description: Describes the natural language(s) of the intended audience for the enclosed entity. Note that this might not be equivalent to all the languages used within the entity-body.
type: string
GCCX-TransactionId:
description: Id to trace the request for debugging purposes
type: string
X-B3-TraceId:
description: Sleuth trace id used to trace multiple requests
type: string
X-B3-SpanId:
description: Sleuth span id used for a single unit of work
type: string
schema:
$ref: '#/definitions/MyDataResponse'
'400':
$ref: "#/responses/BadRequest"
'401':
$ref: "#/responses/Unauthorized"
'403':
$ref: "#/responses/Forbidden"
'404':
$ref: "#/responses/NotFound"
'406':
$ref: "#/responses/NotAcceptable"
'415':
$ref: "#/responses/UnsupportedMediaType"
'429':
$ref: "#/responses/TooManyRequests"
'500':
$ref: "#/responses/InternalServerError"
'503':
$ref: "#/responses/ServiceUnavailable"
MyDataResponse:
type: object
required:
- requestId
- success
- datalist
- failureInfo
properties:
requestId:
type: string
success:
type: boolean
datalist:
type: array
items:
$ref: '#/definitions/DataEntry'
failureInfo:
$ref: "#/definitions/FailureInfo"
DataEntry:
type: object
required:
- names
- id
The groovy test gets autogenerated into the following java test:
#Test
public void validate_myAPI() throws Exception {
// given:
MockMvcRequestSpecification request = given()
.header("Content-Type", "application/json");
// when:
ResponseOptions response = given().spec(request)
.get("path/myAPI/id");
// then:
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.header("Content-Type")).matches("application/json.*");
// and:
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).field("['requestId']").isEqualTo("id");
assertThatJson(parsedJson).field("['success']").isEqualTo(true);
assertThatJson(parsedJson).array("['dataList']").contains("['id']").isEqualTo(100);
assertThatJson(parsedJson).array("['dataList']").array("['names']").arrayField().isEqualTo("aaaa").value();
assertThatJson(parsedJson).array("['dataList']").array("['names']").arrayField().isEqualTo("ffff").value();
assertThatJson(parsedJson).field("['failureInfo']").field("['failureCode']").isEqualTo(100);
assertThatJson(parsedJson).field("['failureInfo']").field("['failureDesc']").isEqualTo("failure");
When I run this test, it fails when trying to get the id field from the data list, with the following exception.
java.lang.RuntimeException: com.jayway.jsonpath.PathNotFoundException: Missing property in path $['datalist']
Running in debug mode, I can verify that the parsedJson does have the dataList map and the elements contained within, but fails to find them during the test. Does anyone have any ideas on what might be causing the issue or what steps I could take to debug the issue? Per company policy, I have changed all use case specific types/apis to generic versions (i.e. myAPI, dataList, etc), so any capitalization issues or naming discrepencies are likely due to my transcribing of the code rather than any issues. All of my component and functional tests pass without issue, so I believe this is just an issue with how I set up my contract test file
Related
Reason: Failed to Install Helm Chart [ fk-m3-matching-engine-cache-service:1.4.6 ] =\u003e cannot patch \"matching-engine-cache-service\" with kind Rollout: admission webhook \"webhook-svc.webhook.svc\" denied the request: unmarshal raw request object to rollout failed: json: cannot unmarshal array into Go struct field Volume.spec.template.spec.volumes.configMap of type v1.ConfigMapVolumeSource\n","severity":0}
cfg-config.yml -->
apiVersion: v1
kind: ConfigMap
metadata:
name: cs-config
namespace: {{ .Values.metadata.namespace }}
data:
cfg-api: |+
host=10.83.47.156
I am not sure why this file is throwing error. Consider me a noob in kube, the data host=10.83.47.156 should be printed in the cfg-api file.
Not sure, but data: cfg-api is not with proper indentation
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
cfg-api: |-
host=10.83.47.156
Instead of host set the helm template properly
I want to apply the following yaml multiple times with the fabric8 kubernetes-client
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: my-storage-class
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
I apply the yaml using createOrReplace()
Config config = new ConfigBuilder()
.withMasterUrl("https://my-kubernetes-root:6443")
.withNamespace("my-namespace")
.withOauthToken(token)
.withTrustCerts(true)
.build();
KubernetesClient client = new DefaultKubernetesClient(config);
ClasspathResource resource = new ClasspathResource("my-pvc.yaml");
client.load(resource.getInputStream()).createOrReplace(); // this works
TimeUnit.MINUTES.sleep(1); // volumeName is dynamically assigned during this period
client.load(resource.getInputStream()).createOrReplace(); // this fails
This works the first time (when the PVC does not exist in the namespace) but fails the second time that createOrReplace() is called for the same yaml with the following error
io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: PUT at: https://my-kubernetes-root:6443/api/v1/namespaces/my-namespace/persistentvolumeclaims/my-pvc. Message: PersistentVolumeClaim "my-pvc" is invalid: spec: Forbidden: spec is immutable after creation except resources.requests for bound claims
core.PersistentVolumeClaimSpec{
AccessModes: []core.PersistentVolumeAccessMode{"ReadWriteMany"},
Selector: nil,
Resources: core.ResourceRequirements{Requests: core.ResourceList{s"storage": {i: resource.int64Amount{value: 1073741824}, s: "1Gi", Format: "BinarySI"}}},
- VolumeName: "",
+ VolumeName: "pvc-b79ebfcb-d5cb-4450-9f17-d69ec10b8712",
StorageClassName: &"my-storage-class",
VolumeMode: &"Filesystem",
DataSource: nil,
}
Notice how "volumeName" is not present in the yaml (nil) but in the error message "volumeName" is changing from empty string to the dynamically assigned volumeName.
I can reproduce this exact same behavior using kubectl and empty string for volumeName
I can kubectl apply the following yaml as many times as I like
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: my-storage-class
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
But if I kubectl apply a yaml with volumeName of empty string it works the first time and fails the second time (The error message is the same as above)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: my-storage-class
volumeName: ""
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
How can I get KubernetesClient to behave the same as kubectl apply? Is there any way that I can apply the same PersistentVolumeClaim yaml multiple times with KubernetesClient?
As a workaround, I have switched to using a StatefulSet to manage my Pod which allows me to specify volumeClaimTemplates
eg the following yaml can be applied multiple times:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: "nginx"
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: k8s.gcr.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "my-storage-class"
resources:
requests:
storage: 1Gi
Kubernetes API doesn't allow you to change some fields for a certain resource type at a certain state. For a PVC, after its state is Bound, the volumeName field in its spec is immutable; you can't change the volume your PVC is referencing.
When you apply a bare PersistentVolumeClaim manifest like the one in your question (a manifest that has no volumeName key or the value of its volumeName is nil), If the cluster has a default StorageClass, it automatically creates a corresponding PersistentVolume object that's the abstraction of your volume in Kubernetes from the underlying storage provider, then assigns its name to your PersistentVolumeClaim with the volumeName key.
After a PersistentVolumeClaim gets bound to a PersistentVolume and its volumeName field gets populated, you can not edit or patch its volumeName field anymore; that's the reason your kubectl apply command fails for the second time.
It's now clear that a Replace verb is not gonna work for a PVC in Bound state. You can Create one and edit or Patch 'some' of its fields (like increasing the size). I'm not familiar with Java SDK, but it should include some APIs for creating, getting, patching, and deleting a PVC.
You can first check for the existence of your PVC using the GetNamespacedPersistentVolumeClaim API; then, if it's not in the cluster, create it using CreateNamespacedPersistentVolumeClaim API. Referencing the axiom: "Explicit is better than Implicit."
I raised this issue on the facric8 kubernetes-client codebase and got an interesting response which may do what I want. Please note that I haven't tried yet since I have a workaround using StatefulSet and volumeClaimTemplates (see my other answer)
The problem is the replace operation. It is not a substitute for apply / patch. Instead of createOrReplace you can use the new support for server side apply
And the relevant section from the link
Server Side Apply Basic usage of server side apply is available via
Patchable. At it's simplest you just need to call:
client.services().withName("name").patch(PatchContext.of(PatchType.SERVER_SIDE_APPLY), service);
For any create or update. This can be a good alternative to
using createOrReplace as it is always a single api call and does not
issue a replace/PUT which can be problematic.
If the resources may be created or modified by something other than a
fabric8 patch, you will need to force your modifications:
client.services().withName("name").patch(new PatchContext.Builder().withPatchType(PatchType.SERVER_SIDE_APPLY).withForce(true).build(), service);
getting error as should be object in line number 2
paths:
error getting here--> /patients/{patientId}/product/
get:
summary: Gets all active products recorded for the patient
description: We will get all the history of the products for a patient given.
tags:
- blood bank
parameters:
in: path
name: patientId
description: Unique id of a patient
required: True
schema:
type: String
responses:
200:
description: OK success
schema:
$ref: "#/components/schemas/product"
409:
description: Conflict
schema:
$ref: '#/components/responses/409'
404:
description: Not Found
$ref: '#/components/responses/404'
406:
description: Not acceptable
$ref: '#/components/responses/406'
post:
summary: Sends all the products details of the patients.
parameters:
- name: ProdId
description: Unique Id of a products
in: query
required: true
schema:
type: string
- name: ProdName
description: Name of the products
in: query
required: true
schema:
type: string
- name: prodDesc
description: Description of the products
in: query
required: true
schema:
type: string
responses:
200:
description: List of products for the patient.
schema:
$ref: '#/components/schemas/productlist'
404:
description: Not Found
schema:
$ref: '#/components/responses/404'
406:
description:
schema:
$ref: '#/components/responses/406'
delete:
tags:
summary: Deletes provided patient information
parameters:
- name: ProdId
description: Unique Id of a products to be deleted
in: path
required: true
type: string
responses:
'200':
description: Successfully Deleted
schema:
$ref: '#/components/schemas/product'
'401':
description: Authentication Failed
schema:
$ref: '#/components/responses/401'
'404':
description: Not Found
schema:
$ref: '#/components/responses/404'
'409':
description: Conflict
schema:
$ref: '#/components/responses/409'
'500':
description: Server error
schema:
$ref: '#/components/responses/500'
I am new to the world of Swagger, trying to implement it for my own application. My problem is that SwaggerUi doesn't take my swagger.yml file but takes it into controller. In fact, I have problems with authentication.
Swagger.yml
swagger: "2.0"
info:
version: "1.1"
title: ABC Operations
termsOfService: http://swagger.io/terms/
host: <HOST>
basePath: /abc/operations
tags:
- name: Stored Message
description: Stored Message Operations
schemes:
- http
- https
security:
- basic_auth: []
paths:
/stored-message/{transactionId}:
get:
tags:
- Stored Message
summary: Stored Message Retrieval by TransactionId
produces:
- application/json
parameters:
- in: path
name: transactionId
required: true
type: string
responses:
200:
description: OK
schema:
type: object
404:
description: Not Found
500:
description: Internal Server Error
put:
tags:
- Stored Message
summary: Stored Message Update
consumes:
- application/json
produces:
- application/json
parameters:
- in: path
name: transactionId
required: true
type: string
- in: body
name: Modified Stored Message
schema:
type: object
responses:
200:
description: OK
404:
description: Not Found
500:
description: Internal Server Error
securityDefinitions:
basic_auth:
type: basic
externalDocs:
description: Find out more about Swagger
url: http://swagger.io
In fact in the SwaggerUi part it does not fill in the new field by default.
How can I make swagger Ui fetch data from swagger.yml?
In your "application.property" file you have to add this string
springdoc.swagger-ui.url: /yourfilename.yml
of and specify the yml file you want to use to start the swaggerUi.
The file must be inside src-> resource->static to be viewed. I recommend that you see the official documentation on the Springdoc website https://springdoc.org/faq.html.
Good day
I have seen a few posts here on stack that show how to create a simplePointLayer. However, the process is failing for me.
I am using Neo4J version 3.0.2 and the spatial plugin version 3.0.2.
I have been here, here, and here.
Each of these pages contains the same set of instructions for creating a SimplePointLayer, as shown below.
This step works just fine for me:
POST /db/data/ext/SpatialPlugin/graphdb/addSimplePointLayer HTTP/1.1
Host: localhost:7474
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache
{
"layer" : "geom",
"lat" : "lat",
"lon" : "lon"
}
I'm not sure where to see a listing of layers, but the response is 200, so I'm assuming everything works as expected here.
The following step is where I am stuck:
POST /db/data/index/node/ HTTP/1.1
Host: localhost:7474
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache
{
"name" : "geom",
"config" : {
"provider" : "spatial",
"geometry_type" : "point",
"lat" : "lat",
"lon" : "lon"
}
}
I have the json above in a file tmp.json and I run
cat tmp.json | http :7474/db/data/index/node
This generates the following message:
HTTP/1.1 400 Bad Request
Access-Control-Allow-Origin: *
Content-Length: 6887
Content-Type: application/json; charset=UTF-8
Date: Wed, 06 Jul 2016 18:14:18 GMT
Server: Jetty(9.2.9.v20150224)
{
"errors": [
{
"code": "Neo.DatabaseError.General.UnknownError",
"message": "No index provider 'spatial' found. Maybe the intended provider (or one more of its dependencies) aren't on the classpath or it failed to load.",
"stackTrace": "java.lang.IllegalArgumentException: No index provider 'spatial' found. Maybe the intended provider (or one more of its dependencies) aren't on the classpath or it failed to load.\n\tat org.neo4j.kernel.NeoStoreDataSource$1.apply(NeoStoreDataSource.java:386)\n\tat org.neo4j.kernel.NeoStoreDataSource$1.apply(NeoStoreDataSource.java:378)\n\tat org.neo4j.kernel.impl.index.LegacyIndexStore.findIndexConfig(LegacyIndexStore.java:105)\n\tat org.neo4j.kernel.impl.index.LegacyIndexStore.getOrCreateIndexConfig(LegacyIndexStore.java:171)\n\tat org.neo4j.kernel.impl.index.LegacyIndexStore.getOrCreateNodeIndexConfig(LegacyIndexStore.java:64)\n\tat org.neo4j.kernel.impl.api.StateHandlingStatementOperations.nodeLegacyIndexCreateLazily(StateHandlingStatementOperations.java:1475)\n\tat org.neo4j.kernel.impl.api.OperationsFacade.nodeLegacyIndexCreateLazily(OperationsFacade.java:1195)\n\tat org.neo4j.kernel.impl.coreapi.IndexProviderImpl.getOrCreateNodeIndex(IndexProviderImpl.java:52)\n\tat org.neo4j.kernel.impl.coreapi.IndexManagerImpl.forNodes(IndexManagerImpl.java:81)\n\tat org.neo4j.server.rest.web.DatabaseActions.createNodeIndex(DatabaseActions.java:381)\n\tat org.neo4j.server.rest.web.RestfulGraphDatabase.jsonCreateNodeIndex(RestfulGraphDatabase.java:845)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat java.lang.reflect.Method.invoke(Method.java:498)\n\tat com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)\n\tat com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205)\n\tat com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)\n\tat org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:144)\n\tat com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302)\n\tat com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)\n\tat com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)\n\tat com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)\n\tat com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)\n\tat com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1542)\n\tat com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1473)\n\tat com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1419)\n\tat com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1409)\n\tat com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:409)\n\tat com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:558)\n\tat com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:733)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:790)\n\tat org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:808)\n\tat org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)\n\tat org.neo4j.server.rest.web.CollectUserAgentFilter.doFilter(CollectUserAgentFilter.java:69)\n\tat org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)\n\tat org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)\n\tat org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:221)\n\tat org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)\n\tat org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)\n\tat org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)\n\tat org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)\n\tat org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)\n\tat org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:52)\n\tat org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)\n\tat org.eclipse.jetty.server.Server.handle(Server.java:497)\n\tat org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)\n\tat org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)\n\tat org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)\n\tat org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)\n\tat org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)\n\tat java.lang.Thread.run(Thread.java:745)\n"
}
],
"exception": "IllegalArgumentException",
"fullname": "java.lang.IllegalArgumentException",
"message": "No index provider 'spatial' found. Maybe the intended provider (or one more of its dependencies) aren't on the classpath or it failed to load.",
"stackTrace": [
"org.neo4j.kernel.NeoStoreDataSource$1.apply(NeoStoreDataSource.java:386)",
"org.neo4j.kernel.NeoStoreDataSource$1.apply(NeoStoreDataSource.java:378)",
"org.neo4j.kernel.impl.index.LegacyIndexStore.findIndexConfig(LegacyIndexStore.java:105)",
"org.neo4j.kernel.impl.index.LegacyIndexStore.getOrCreateIndexConfig(LegacyIndexStore.java:171)",
"org.neo4j.kernel.impl.index.LegacyIndexStore.getOrCreateNodeIndexConfig(LegacyIndexStore.java:64)",
"org.neo4j.kernel.impl.api.StateHandlingStatementOperations.nodeLegacyIndexCreateLazily(StateHandlingStatementOperations.java:1475)",
"org.neo4j.kernel.impl.api.OperationsFacade.nodeLegacyIndexCreateLazily(OperationsFacade.java:1195)",
"org.neo4j.kernel.impl.coreapi.IndexProviderImpl.getOrCreateNodeIndex(IndexProviderImpl.java:52)",
"org.neo4j.kernel.impl.coreapi.IndexManagerImpl.forNodes(IndexManagerImpl.java:81)",
"org.neo4j.server.rest.web.DatabaseActions.createNodeIndex(DatabaseActions.java:381)",
"org.neo4j.server.rest.web.RestfulGraphDatabase.jsonCreateNodeIndex(RestfulGraphDatabase.java:845)",
"java.lang.reflect.Method.invoke(Method.java:498)",
"org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:144)",
"org.neo4j.server.rest.web.CollectUserAgentFilter.doFilter(CollectUserAgentFilter.java:69)",
"java.lang.Thread.run(Thread.java:745)"
]
}
I'm not sure where to go from here. I am assuming the 'provider' is the plugin. I am not a JAVA person, so I'm not sure how to deal with classpaths. Has anyone encountered this error before \ know how to deal with this problem?
The spatial library is in a bit of flux at the moment with the introduction of user defined procedures in Neo4j 3.0. Specifically:
Procedures are becoming the recommended way to interact with spatial, and
The index provider has been removed from the spatial library (causing the error you encountered)
With procedures you now have access to spatial functionality from Cypher:
Create layer
CALL spatial.addPointLayer('cities');
Add all cities to the layer
MATCH (c:City)
WITH collect(c) AS cities
CALL spatial.addNodes('cities',cities) YIELD node
RETURN count(*)
Find cities within distance
MATCH (c:City {name:"Berlin"}) WITH c
CALL spatial.distance('cities', c , 200) YIELD node, distance
RETURN node.name AS name, round(distance) AS dist
See this for more info.