Skip to main content
Version: 2.0

Showme

Dynamic APIs are integral to how users interact with data. GraphGrid Showmes allow developers to create their own APIs using only Geequel. In this tutorial you will learn the basics of Showmes using ONgDB's movie dataset. We recommend completing the Movie Database tutorial before moving on to this one. The Movie Database tutorial teaches you how to make your own graph using ONgDB's movie dataset, and how to visualize it in the Dashboard. We'll be using those basics in this tutorial.

Showme Module Tutorial Overview

  1. /getMoviesByYear Showme
    • Create a Showme called getMoviesByYear.
    • Execute the/getMoviesByYear Showme.
  2. /shortestPath Showme
    • Create a Showme called shortestPath
    • Execute the shortestPath Showme.
  3. Add a Showme to the Dashboard.

Create a Showme

/getMoviesByYear

Let's make a Showme that will create an endpoint that will allow a user to return a list of movies released in a certain year. Now that we have defined what we want our endpoint to do, we need to answer the following questions:

What query will need to be run to access the data that we need?

We know that we'll need to query nodes with a Movie label that match the value of the parameter released. We can pass in this Geequel into our request:

MATCH (m:Movie {released:$released}) RETURN m

What is the method of this request?

Since we are retrieving information from the database the method for this endpoint will be a GET request.

What do we want to name our path?

/getMoviesByYear sounds good!

What parameters will we need to include and/or require in this request?

In order for this request to be successful we need to include in our params released as a key.

The entire /createShowme request including the body we created will look like this:

note

You can use either the /createShowme and /updateShowme to create a Showme. Just note that for /updateShowme has slightly different parameters. Instead of nodeTypeGrns and params /updateShowme uses addNodeTypeGrns and addParams.

curl --location --request POST "${API_BASE}/1.0/showme/createShowme" \
--header "Authorization: Bearer ${BEARER_TOKEN}" \
--header 'Content-Type: application/json' \
--data-raw '
{
"cypher": "MATCH (m:Movie {released:$released}) RETURN m",
"showmeMethod": "GET",
"showmePath": "/getMoviesByYear",
"showmeDisplayValue": "getMoviesByYear",
"showmeDefinition": "Returns a list of movies released in a specific year",
"showmePopulatorDisplayValue": "getMoviesByYear",
"showmePopulatorDefinition": "getMoviesByYear",
"nodeTypeGrns": [],
"params": {
"released": ""
},
"requiredParams": [],
"cypherOrder": 0,
"overrideCypherOrder": false
}'

And the response will look like this:

{
"showme": {
"id": 66,
"labels": [],
"enver": 0,
"createdAt": "2021-04-27T16:43:33.164Z",
"updatedAt": "2021-04-27T16:43:33.164Z",
"createdBy": "graphgrid",
"lastModifiedBy": "graphgrid",
"grn": "grn:gg:graphgridshowme:HrT9QxjdnnVoV0owQODCnD00zrPHuyul4cTjmXypWWp1",
"key": "GET /getMoviesByYear",
"method": "GET",
"path": "/getMoviesByYear",
"definition": "Returns a list of movies released in a specific year",
"displayValue": "getMoviesByYear",
"order": null,
"disableUserRoleRequirement": null,
"nodeTypes": [],
"showmePopulator": {
"id": 65,
"labels": [],
"enver": 0,
"createdAt": "2021-04-27T16:43:33.152Z",
"updatedAt": "2021-04-27T16:43:33.179Z",
"createdBy": "graphgrid",
"lastModifiedBy": "graphgrid",
"grn":"grn:gg:graphgridshowmepopulator:3Bb7MPFpJ5xtHh6nsYL2YMjVAJQsRfwxjSIz820WWRKI",
"cypher": "MATCH (m:Movie {released:$released}) RETURN m",
"displayValue": "getMoviesByYear",
"definition": "getMoviesByYear",
"requiredParameters": [],
"searchQuery": null,
"successRoutes": [],
"failureRoutes": [],
"conditionalSuccessRoutes": [],
"conditionalFailureRoutes": [],
"parameters": [
{
"id": 305,
"labels": [],
"enver": 0,
"createdAt": "2021-04-27T16:43:33.154Z",
"updatedAt": "2021-04-27T16:43:33.154Z",
"createdBy": "graphgrid",
"lastModifiedBy": "graphgrid",
"grn": "grn:gg:graphgridshowmeparameter:sizHGDyypOprw1pkn3UccpdqAzhJyzjM07NyGY5wMIAA",
"type": "java.util.LinkedHashMap",
"key": "released",
"value": "{}",
"encryption": null,
"grnType": "graphgridshowmeparameter",
"label": "GraphGridShowmeParameter"
}
],
"snippets": [],
"snippetImpls": null,
"cypherOrder": 0,
"grnType": "graphgridshowmepopulator",
"label": "GraphGridShowmePopulator"
},
"securityRules": null,
"grnType": "graphgridshowme",
"label": "GraphGridShowme"
},
"showmePopulator": {
"id": 65,
"labels": [],
"enver": 0,
"createdAt": "2021-04-27T16:43:33.152Z",
"updatedAt": "2021-04-27T16:43:33.179Z",
"createdBy": "graphgrid",
"lastModifiedBy": "graphgrid",
"grn": "grn:gg:graphgridshowmepopulator:3Bb7MPFpJ5xtHh6nsYL2YMjVAJQsRfwxjSIz820WWRKI",
"cypher": "MATCH (m:Movie {released:$released}) RETURN m",
"displayValue": "getMoviesByYear",
"definition": "getMoviesByYear",
"requiredParameters": [],
"searchQuery": null,
"successRoutes": [],
"failureRoutes": [],
"conditionalSuccessRoutes": [],
"conditionalFailureRoutes": [],
"parameters": [
{
"id": 305,
"labels": [],
"enver": 0,
"createdAt": "2021-04-27T16:43:33.154Z",
"updatedAt": "2021-04-27T16:43:33.154Z",
"createdBy": "graphgrid",
"lastModifiedBy": "graphgrid",
"grn": "grn:gg:graphgridshowmeparameter:sizHGDyypOprw1pkn3UccpdqAzhJyzjM07NyGY5wMIAA",
"type": "java.util.LinkedHashMap",
"key": "released",
"value": "{}",
"encryption": null,
"grnType": "graphgridshowmeparameter",
"label": "GraphGridShowmeParameter"
}
],
"snippets": [],
"snippetImpls": null,
"cypherOrder": 0,
"grnType": "graphgridshowmepopulator",
"label": "GraphGridShowmePopulator"
}
}

/executeShowme/getMoviesByYear

Now we can see our newly created endpoint in action by executing the Showme. Run this request passing in the path of our Showme /getMoviesByYear and our params {"released":1999}. This /executeShowme request should return the results for the key "released" that has a value of 1999.

note

Parameters must be URL encoded for GET requests.

curl --location --request GET "${API_BASE}/1.0/showme/executeShowme/getMoviesByYear?params=%7B%22released%22%3A1999%7D" \
--header "Authorization: Bearer ${BEARER_TOKEN}"

Our response shows a list of movies that were released in 1999:

{
"results": [
{
"m": {
"labels": [
"Resource",
"Movie",
"GraphGridResource"
],
"id": 18,
"properties": {
"createdAt": "2021-04-26T20:19:55+00:00",
"grn": "grn:gg:movie:HCzJLaDkzJL3EvkGHMBIwDHxmb6xKPSshu9DLihqNuaI",
"lastSearchIndexedAt": "0",
"tagline": "One robot's 200 year journey to become an ordinary man.",
"title": "Bicentennial Man",
"released": 1999,
"updatedAt": "2021-04-26T20:19:55+00:00"
}
}
},
{
"m": {
"labels": [
"Resource",
"Movie",
"GraphGridResource"
],
"id": 46,
"properties": {
"createdAt": "2021-04-26T20:19:55+00:00",
"grn": "grn:gg:movie:ryRIh16x7oMFrkf9IX9Xx70HLyR8unhm8cXOvEDbZIBY",
"lastSearchIndexedAt": "0",
"tagline": "Walk a mile you'll never forget.",
"title": "The Green Mile",
"released": 1999,
"updatedAt": "2021-04-26T20:19:55+00:00"
}
}
},
{
"m": {
"labels": [
"Resource",
"Movie",
"GraphGridResource"
],
"id": 103,
"properties": {
"createdAt": "2021-04-26T20:19:55+00:00",
"grn": "grn:gg:movie:pHwiHrVucvcsifSO2A58X6QiCYdvkiA4SSaFSdCXFD1d",
"lastSearchIndexedAt": "0",
"tagline": "Welcome to the Real World",
"title": "The Matrix",
"released": 1999,
"updatedAt": "2021-04-26T20:19:55+00:00"
}
}
},
{
"m": {
"labels": [
"Resource",
"Movie",
"GraphGridResource"
],
"id": 165,
"properties": {
"createdAt": "2021-04-26T20:19:55+00:00",
"grn": "grn:gg:movie:0mTK8k4FJ6Nrl9sPNVVTbdHIqPQgyOynYUX9Tr727VH7",
"lastSearchIndexedAt": "0",
"tagline": "First loves last. Forever.",
"title": "Snow Falling on Cedars",
"released": 1999,
"updatedAt": "2021-04-26T20:19:55+00:00"
}
}
}
],
"bookmark": "neo4j:bookmark:v1:tx2175",
"errors": []
}

/shortestPath

This Showme example is a bit more advanced, but presents just how much Showmes can be customized to handle your data to get interesting insights! The /shortestPath Showme will take in two parameters of two person nodes. The Showme will return the shortest path through edgeType relationships between them.

The Geequel query we need to run to get the shortest path between two nodes will looks like this:

MATCH (p1:Person) WHERE p1.grn = {firstPersonGrn} MATCH (p2:Person) WHERE p2.grn = {secondPersonGrn} MATCH p=allShortestPaths((p1)-[*]-(p2)) WHERE NONE(n IN nodes(p) WHERE n:Version) WITH nodes(p) AS shortestPathNodes UNWIND shortestPathNodes AS shortestPathNode RETURN COLLECT(shortestPathNode.grn) AS nodeIds

This query sets two parameters: firstPersonGrn and secondPersonGrn and uses all edgeTypes to find the shortest path between them.

Here's the full create Showme request:

curl --location --request PUT "${API_BASE}/1.0/showme/updateShowme/shortestPath" \
--header 'Content-Type: application/json' \
--header "Authorization: Bearer ${BEARER_TOKEN}" \
--data-raw '{
"cypher": "MATCH (p1:Person) WHERE p1.grn = {firstPersonGrn} MATCH (p2:Person) WHERE p2.grn = {secondPersonGrn} MATCH p=allShortestPaths((p1)-[*]-(p2)) WHERE NONE(n IN nodes(p) WHERE n:Version) WITH nodes(p) AS shortestPathNodes UNWIND shortestPathNodes AS shortestPathNode RETURN COLLECT(shortestPathNode.grn) AS nodeIds",
"showmeMethod": "GET",
"showmePath": "/shortestPath",
"showmeDisplayValue": "shortestPath",
"showmeDefinition": "shortest path between two people",
"showmePopulatorDisplayValue": "shortestPath",
"showmePopulatorDefinition": "shortestPath",
"addNodeTypeGrns": [],
"addParams": {
"firstPersonGrn": "",
"secondPersonGrn": ""
},
"requiredParams": ["firstPersonGrn","secondPersonGrn"],
"cypherOrder": 0,
"overrideCypherOrder": false
}
'

/executeShowme/shortestPath

Let's see our Showme in action! Run the /executeShowme request with URL encoded params for firstPersonGrn and secondPersonGrn. This request queries the shortest path between Keanu Reeves and Al Pacino.

curl --location --request GET "${API_BASE}/1.0/showme/executeShowme/shortestPath?params=%7B%22firstPersonGrn%22%3A%22grn%3Agg%3Aperson%3AVd0D6CdJ4T3RmkYhyCAneDFEX5WJWU9H1P450TsPXhT9%22%2C%20%22secondPersonGrn%22%3A%22grn%3Agg%3Aperson%3ApKMmKbKTseEGadwaM3EYOBrvKlTJpr5ICctdnfNYv4DP%22%7D" \
--header "Authorization: Bearer ${BEARER_TOKEN}"

Response:

{
"results": [{
"shortestPathNodes": [{
"labels": [
"Resource",
"Person",
"GraphGridResource"
],
"id": 355,
"properties": {
"createdAt": "2021-04-28T21:52:29+00:00",
"grn":"grn:gg:person:Vd0D6CdJ4T3RmkYhyCAneDFEX5WJWU9H1P450TsPXhT9",
"lastSearchIndexedAt": "0",
"born": 1940,
"name": "Al Pacino",
"updatedAt": "2021-04-28T21:52:29+00:00"
}
},
{
"labels": [
"Resource",
"Movie",
"GraphGridResource"
],
"id": 353,
"properties": {
"createdAt": "2021-04-28T21:52:29+00:00",
"grn": "grn:gg:movie:pO3MA539rBvsA4LXU26G0tFHm1vUDfznq1P3gksl6YeI",
"lastSearchIndexedAt": "0",
"tagline": "Evil has its winning ways",
"title": "The Devil's Advocate",
"released": 1997,
"updatedAt": "2021-04-28T21:52:29+00:00"
}
},
{
"labels": [
"Resource",
"Person",
"GraphGridResource"
],
"id": 343,
"properties": {
"createdAt": "2021-04-28T21:52:29+00:00",
"grn":
"grn:gg:person:pKMmKbKTseEGadwaM3EYOBrvKlTJpr5ICctdnfNYv4DP",
"lastSearchIndexedAt": "0",
"born": 1964,
"name": "Keanu Reeves",
"updatedAt": "2021-04-28T21:52:29+00:00"
}
}
]
}],
"bookmark": "neo4j:bookmark:v1:tx6495",
"errors": []
}

The response returns the shortest path between our two person nodes, which is that they both acted in "The Devil's Advocate." We can see and use our Showmes through the GraphGrid Dashboard. Now that we know more about the API calls, let's get a Showme working in the dashboard!

Showmes in The Dashboard

Getting Showmes to appear in the GraphGrid Dashboard takes some setup through GraphGrid Manager Models. A manager model shows what nodes, relationships, and properties are allowed and how they can be structured.

Setup Steps

These are the steps required to display a Showme in the dashboard:

Generate a Manager Model Policy
Get Manager Grn
Generate a Manager Model Graph
Create getNodeTypeGrns Showme
Execute getNodeTypeGrns Showme
Create your custom Showme

Generate a Manager Model Policy

A ManagerModelPolicy (MMP) is a JSON policy which is used to generate the NodeType, EdgeType, Property, PropertyImpl, and versioning nodes of a manager model.
For our Movie Database we want to include the Movie and Person node labels.

curl --location --request POST "${API_BASE}/1.0/manager/model/policy/default/generateManagerPolicy/default-manager-model-policy" \
--header 'Content-Type: application/json' \
--header "Authorization: Bearer ${BEARER_TOKEN}" \
--data-raw '{
"includeLabels":
[
"Person",
"Movie"
],
"excludeRelationships":[]
}'

Generate a Manager Model Graph

Using our manager model policy and our manager node, we need to generate a manager model graph. This request essentially prepares our manager model policy to set up parameters that are required for the graph to recognize our nodetypes. The name of our manager model policy and our manager grn are required parameters for this request. This request requires the manager node grn. The default manager node grn is grn:gg:manager:default If you are using a different manager version with a different node, you can retrieve its grn by using this Manager endpoint to retrieve it by its name.

curl --location --request POST "${API_BASE}/1.0/manager/model/policy/generateManagerModelGraph/default/default-manager-model-policy/grn:gg:manager:default' \
--header 'Content-Type: application/json" \
--header "Authorization: Bearer ${BEARER_TOKEN}"

Add NodeType Grns to a Showme

Next we'll need to grab the nodeTypeGrns for both Person and Movie nodes. To do this we can run these this query in ONgDB (remember that ONgDB can be acces in the browser at port 7474):

MATCH (a:NodeType {key:"Person"}) MATCH (b:NodeType {key: "Movie"}) RETURN a.grn, b.grn

Next we'll need to copy these two grns. These can be added to any custom Showme in the request body under the nodeTypeGrns key. For this tutorial we'll add it to the /shortestPath Showme.

This is what the request looks like with the nodeTypeGrns added to the Showme:

curl --location --request PUT "${API_BASE}/1.0/showme/updateShowme/shortestPath" \
--header 'Content-Type: application/json' \
--header "Authorization: Bearer ${BEARER_TOKEN}" \
--data-raw '{
"cypher": "MATCH (p1:Person) WHERE p1.grn = {firstPersonGrn} MATCH (p2:Person) WHERE p2.grn = {secondPersonGrn} MATCH p=allShortestPaths((p1)-[*]-(p2)) WHERE NONE(n IN nodes(p) WHERE n:Version) WITH nodes(p) AS shortestPathNodes UNWIND shortestPathNodes AS shortestPathNode RETURN COLLECT(shortestPathNode.grn) AS nodeIds",
"showmeMethod": "GET",
"showmePath": "/shortestPath",
"showmeDisplayValue": "shortestPath",
"showmeDefinition": "shortest path between two people",
"showmePopulatorDisplayValue": "shortestPath",
"showmePopulatorDefinition": "shortestPath",
"addNodeTypeGrns": ["grn:gg:graphgridnodetype:p5m6SZLuqp5rTILpu1zOkVYFPY4x9FzjKIgAbgMPlS18","grn:gg:graphgridnodetype:hRl8GplVHixGMQM1a4B6obNoOT00bhHVzpdOp59cgqDO"],
"addParams": {
"firstPersonGrn": "",
"secondPersonGrn": ""
},
"requiredParams": ["firstPersonGrn","secondPersonGrn"],
"cypherOrder": 0,
"overrideCypherOrder": false
}
'

Run the above request to update the /shortestPath Showme with the proper nodeTypeGrns.

Create Your Custom Showme

Let's see our /shortestPath Showme that we already created in action in the dashboard!

Viewing Showmes in the Dashboard

Head into the GraphGrid Dashboard and create a new project to display our Showme. In the query editor, run a query for 1 person node and add it to the graph. We used the "Al Pacino" node. Select the node and click the Showme button.

Screenshot

And the Showmes tab will appear:

Screenshot

From here you can edit the Showme in order to add parameters and run it.

The shortestPath Showme takes two parameters, firstPersonGrn and secondPersonGrn. Let's use a different grn from our original shortestPath request. Let's setfirstPersonGrn to Carrie-Anne Moss and keep Al Pacino for the secondPersonGrn. These parameters will return the shortest path between these two actors who (according to the data we're using) have not acted in any movies together.

Copy this Geequel query to return the nodes' grn:

MATCH (a:Person {name: "Carrie-Anne Moss"}) MATCH (b:Person {name: "Al Pacino"}) RETURN a.grn, b.grn

Copy and place these grn values in the Showme. Once the parameters are set we can click the "Update Showme" button which will save our parameter values. Making sure our Al Pacino node is still selected, click the plus sign next to the name of the Showme.

Screenshot

Clicking this button will execute our Showme with our set parameters and will then appear in the graph.

Screenshot

Our Showme returned the shortest path between Al Pacino and Carrie-Anne Moss! Carrie-Anne starred in the "Matrix" Trilogy with Keanu Reeves who acted in "The Devil's Advocate" with Al Pacino.

note

Showme functionality within the UI is still a work in progress. In order to get the cleanest results from a Showme it's recommended to create a new project. If multiple Showmes are executed on the same project graph the results are added to the Showme nodes already displayed on the graph.

Setting Security Rules

It may be necessary to restrict data access for certain roles within your organization. This section of the tutorial will guide you through setting up a secured showme that performs an authorization and authentication check.

Security protocols are defined under the showmeSecurityRules parameter as a Geequel query in the request body. The security rules set up in a showme are an added layer of security to ensure that only users with the right credentials have access to the information returned by the showme.

To define a showme security rule, a Geequel query will need to return a true or false value. The showme security rule takes in a Geequel query that returns true or false. If the value returns true then the user will be granted access, if it is false access will be denied.

An example of a query that would work as a security rule would be the one below:

OPTIONAL MATCH rel=(principal)-[:HAS_ROLE]->({name:'admin'}) RETURN rel IS NOT NULL

This query looks for a relationship called HAS_ROLE the name "admin". This query will either return true or false.

Another example would be to use the properties passed into the showme itself:

OPTIONAL MATCH (u2:User {grn: $userGrn2})<-[:SECURITY_SPEC]-(principal) WITH u2, principal CALL apoc.util.validate(u2 IS NULL, 'resource cannot be found for ' + $userGrn2 + ' or is not authorized for the user', []) OPTIONAL MATCH (p:SecurityPermission {name: 'Admin'}) RETURN shortestPath((principal)-[*..3]->(p)) IS NOT NULL

The query above uses the properties set in the showme to look for validation within the security parameters set and returns a message if the user is not authorized.

note

You may have noticed the principal in the example Geequel queries. The principal is defined from the user's OAuth Token metadata. The principal value will be defined by the user that is making the API call.

The Geequel query is included within the JSON body of the showme upon creation. The property is called showMeSecurityRules. Its key is "cypherQuery" and the value is the Geequel query that returns true or false.

 "showMeSecurityRules": {
"spelExpression": "permitAll",
"cypherQuery": "WITH principal.name AS name RETURN true"

The above query would permit all users/roles access to the data retrieved by the showme.

Next let's set a security rule that only allows showme access to certain users. First we will create a property on the user node(s) that we want to allow access and set its value to true. This will be the property that the showme API reads in order to authenticate the request.

One way we could do this is to set a property called isAdmin on the user node and give it a value of true. The following query finds a user node by its grn and sets a property called isAdmin to true.

MATCH (principal:User {grn: "grn:gg:user:EeTO5wqULpuk1Xr8T8JQ2VcT5075cTvAWdmpjEDXnl9W"}) SET principal.isAdmin = true

Next we need to write a Geequel query to add to the showme request body that defines the security rules:

  "showmeSecurityRules": {
"cypherQuery": "RETURN principal.isAdmin = true"

A showme with these defined security rules would only allow access to user nodes that have the property isAdmin with the value set to true.

An unauthorized user would get the following message when attempting to access the showme:

{
"timestamp": "2023-09-20T19:30:52.938Z",
"status": 403,
"type": null,
"code": null,
"error": "Forbidden",
"message": "Access is denied; invalid security rule",
"localizedMessage": "Access is denied; invalid security rule",
"path": "/1.0/showme/executeShowme/getMoviesByYear",
"cause": null,
"stacktrace": "org.springframework.security.access.AccessDeniedException: Access is denied; invalid security rule\n\tat com.graphgrid.boot.security.showme.service.ShowmeAuthorizeServiceImpl.checkAuthorized(ShowmeAuthorizeServiceImpl.java:96)\n\tat com.graphgrid.boot.manager.service.ShowmeServiceImpl.executeShowme(ShowmeServiceImpl.java:765)\n\tat com.graphgrid.boot.manager.service.ShowmeServiceImpl$$FastClassBySpringCGLIB$$e05dba31.invoke(<generated>)\n\tat org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)\n\tat org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684)\n\tat com.graphgrid.boot.manager.service.ShowmeServiceImpl$$EnhancerBySpringCGLIB$$b99c3914.executeShowme(<generated>)\n\tat com.graphgrid.boot.manager.controller.ShowmeController.lambda$executeShowme$0(ShowmeController.java:261)\n\tat org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler$StreamingResponseBodyTask.call(StreamingResponseBodyReturnValueHandler.java:110)\n\tat org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler$StreamingResponseBodyTask.call(StreamingResponseBodyReturnValueHandler.java:97)\n\tat org.springframework.web.context.request.async.WebAsyncManager.lambda$startCallableProcessing$4(WebAsyncManager.java:326)\n\tat java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)\n\tat java.util.concurrent.FutureTask.run(FutureTask.java:266)\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n\tat java.lang.Thread.run(Thread.java:750)\n"
}

The message returns as access denied due to invalid security rule. User nodes that do not have the isAdmin property set to true are not authorized to access this showme.

note

When setting the value of the property defined in the showmeSecurityRules query, the query must return a valid boolean value of true. Anything other than true would result in denied access. When setting these properties on user nodes ensure that the value is set to true and not a string "true".