Developing a app using JSON¶
Developing an app involves connecting to Hydra through its SOAP or JSON API. Here we provide an example of simple app, which retrieves a network. This example uses the requests python library to connect to JSON api.
Creating a client¶
First, the WSDL must be identified and connected to the library.
By default, the hydra server is hosted on port 8080: http://localhost:8080/json
from HydraLib.PluginLib import JsonConnection
url = "http://localhost:8080/soap?wsdl"
conn = JsonConnection(url)
Connect to the server¶
As the app connects to a remote server, a login is required so that data is protected.
For local use with one user, this can simply be read from a config file.
Once login is performed, the session_id
must be stored and added to the request
header for all subsequent requests. Hydra provides a library which handles this through
the JsonConnection object. To log in, just call login
like so:
login_response = conn.login('myuser', 'Pa55w0rD')
Creating a network instance¶
Having successfully logged in, networks can be added, accessed and manipulated.
Hydra employs following structure:
Project ->
Networks ->
Nodes ->
Node Attributes
Links ->
Link Attributes
Scenarios ->
Data
This way, a project can contain multiple networks, which can in turn contain multiple scenarios. A scenario represents one ‘state’ of the network.
Before a network can be created, we must first create a project
proj = dict(name = 'SOAP test %s'%(datetime.datetime.now()))
project = conn.call('add_project', {'project':proj})
A network can now be created .. code-block:: python
- net = dict(
name = args.network_name description = “A network created by the example plugin” project_id = project.id #Note that the project now has an ID, after adding it)
Nodes can now be added to the project
node1 = dict(
id = -1
name = "Node 1",
description = "A node representing a water resource",
x = 10,
y = 10,
node2 = dict(
node1.id = -2,
node2.name = "Node 2",
node2.description = "A node representing another water resource",
node2.x = 20,
node2.y = 20,
)
nodes = [node1, node2]
...and now we link the nodes
link = dict(
name = "Link 1",
description = "A link between two water resources",
node_1_id = -1
node_2_id = -2)
links = [link]
network['nodes'] = nodes
network['links'] = linkd
One slight complication with linking nodes is that the nodes do not yet have IDS. So how do the links what they are connecting? For this, temporary negative IDS are used. Notice on the nodes above, they have been assigned negative IDS. These will be replaced by permenant, positive IDS once the data is inserted into hydra. Negative IDs are only necessary if the object needs to be referred to and the referrer is not a direct descendant of the referee.
Now the network can be created
network = conn.call('add_network', {'net':network})
Attributes¶
Hydra provides the feature to assign attributes to nodes and links. For example, data associated with a node representing a water treatment plant might be ‘capacity’, ‘annual energy cost’ or ‘daily throughput’.
To achieve this, first the attributes themselves must be defined. Once an attribute is defined, it does not need to be defined again. It can be used throughout Hydra. A Name and Dimension uniquely define an attribute
#Define the attribute details
name = "Capacity"
dimension = Volume
#Check the attribute does not already exist.
attr = conn.call('get_attribute', ({'name':name, 'dimension':dimension})
if attr is None:
attr = dict(
name = name,
dimen = dimension)
attr = conn.call('get_attribute', ({'attr':attr})
Once the attribute has been defined, it can be assigned to the node. Going back to the network creation example, a node is defined as follows
node2 = dict(
id = -2,
name = "Node 2",
description = "A node representing another water resource",
x = 20,
y = 20,
)
An attribute is added to this node using a ResourceAttr
object.
A ResourceAttr
links a resource (a network, node or link) to a network. Each has
its own id and ref_key, which indicates whether it refers to a node, link or network.
In this example, the node Node 2
is being given attribute Capacity
res_attr = dict(
ref_key = 'NODE'
attr_id = attr.id
id = -1
)
node.attributes. = [res_attr]
Note that a temporary negative ID is once again given to the ResourceAttr. This bears no relation to the negative ID on the node. It will be used later to associate data with this attribute. When the network is saved, this ID will be replaced by a permenant, positive, ID.
Scenarios and Data¶
Node and link attributes are not particularly useful by themselves without them
having a value. Using scenarios, attributes can have multiple values for different
purposes. For example, a network represenging a river network might have two
scenarios: Dry Year
and Wet Year
. While the topology of the network will
not change, the attributes of many of the nodes might change. Daily Throughput
of
our water treatment work will be less in a dry year compared to a wet year, for example.
In order to assign data to specific attributes, a scenario is used
scenario = dict(
name = 'Dry Year',
description = 'Projected scenario of network in a dry year.',
resourcescenarios = []
)
Now data can be added
rs = dict(
resource_attr_id = -1 #This refers to the ID given to the resource attr earlier.
)
dataset = dict(
type = 'descriptor',
name = 'Volume of water in a reservoir during a dry year',
unit = 'ml',
dimension = 'Volume', # THis must match the dimension of the attribute.
hidden = 'N',
value = {'desc_val':100000},
)
rs['value'] = dataset
scenario['resourcescenarios'] = [rs]
net['scenarios'] = [scenario]
#add the network...