/**
  * Get a graph.
  *
  * @param  string $id
  * @return GraphCommons\Graph\Graph
  * @throws GraphCommons\GraphCommonsApiException
  */
 public final function getGraph(string $id) : Graph
 {
     $response = $this->gc->client->get("/graphs/{$id}");
     if (!$response->ok()) {
         $fail = $response->getFail();
         throw new GraphCommonsApiException(sprintf('API error: code(%d) message(%s)', $fail['code'], $fail['message']), $fail['code']);
     }
     // this part is fully oop way for easy data manipulation
     $graph = new Graph();
     $g = $response->getBodyData('graph');
     if (!empty($g)) {
         // covert json graph to object
         $g = Util::toObject($g);
         // set base properties
         $graph->setId($g->id)->setName($g->name)->setSubtitle($g->subtitle)->setDescription($g->description)->setCreatedAt($g->created_at)->setUpdatedAt($g->updated_at)->setStatus($g->status);
         // set graph image as GraphCommons\Graph\Entity\Image
         $image = (new GraphImage($graph))->setPath($g->image->path)->setRefName($g->image->ref_name)->setRefUrl($g->image->ref_url);
         $graph->setImage($image);
         // set graph license as GraphCommons\Graph\Entity\License
         $license = (new GraphLicense($graph))->setType($g->license->type)->setCcBy($g->license->cc_by)->setCcSa($g->license->cc_sa)->setCcNd($g->license->cc_nd)->setCcNc($g->license->cc_nc);
         $graph->setLicense($license);
         // set graph layout as GraphCommons\Graph\Entity\Layout
         $layout = (new GraphLayout($graph))->setSpringLength($g->layout->springLength)->setGravity($g->layout->gravity)->setSpringCoeff($g->layout->springCoeff)->setDragCoeff($g->layout->dragCoeff)->setTheta($g->layout->theta)->setAlgorithm($g->layout->algorithm)->setTransform($g->layout->transform);
         $graph->setLayout($layout);
         // set graph users as GraphCommons\Graph\Entity\Users
         $graph->setUsers(new GraphUsers());
         if (!empty($g->users)) {
             foreach ($g->users as $_) {
                 $id = trim($_->id);
                 if ($id != '') {
                     $user = (new GraphUser($graph))->setId($id)->setUsername($_->username)->setFullName($_->fullname)->setFirstName($_->first_name)->setLastName($_->last_name)->setIsOwner($_->is_owner)->setIsAdmin($_->is_admin)->setImgPath($_->img_path);
                     $graph->users->set($id, $user);
                 }
             }
         }
         // set graph nodes as GraphCommons\Graph\Entity\Nodes
         $graph->setNodes(new GraphNodes());
         if (!empty($g->nodes)) {
             foreach ($g->nodes as $_) {
                 $id = trim($_->id);
                 if ($id != '') {
                     $node = (new GraphNode($graph))->setId($id)->setTypeId($_->type_id)->setName($_->name)->setDescription($_->description)->setImage($_->image)->setReference($_->reference)->setProperties($_->properties)->setPosXY($_->pos_x, $_->pos_y);
                     $graph->nodes->set($id, $node);
                 }
             }
         }
         // set graph nodes types as GraphCommons\Graph\Entity\NodeTypes
         $graph->setNodeTypes(new GraphNodeTypes());
         if (!empty($g->nodeTypes)) {
             foreach ($g->nodeTypes as $_) {
                 $id = trim($_->id);
                 if ($id != '') {
                     $nodeType = (new GraphNodeType($graph))->setId($id)->setName($_->name)->setNameAlias($_->name_alias)->setDescription($_->description)->setImage($_->image)->setImageAsIcon((bool) $_->image_as_icon)->setColor($_->color)->setProperties($_->properties)->setHideName((bool) $_->hide_name)->setSize($_->size)->setSizeLimit($_->size_limit);
                     $graph->nodeTypes->set($id, $nodeType);
                 }
             }
         }
         // set graph edges as GraphCommons\Graph\Entity\Edges
         $graph->setEdges(new GraphEdges());
         if (!empty($g->edges)) {
             foreach ($g->edges as $_) {
                 $id = trim($_->id);
                 if ($id != '') {
                     $edge = (new GraphEdge($graph))->setId($id)->setName($_->name)->setUserId($_->user_id)->setTypeId($_->type_id)->setFrom($_->from)->setTo($_->to)->setWeight($_->weight)->setDirected($_->directed)->setProperties($_->properties);
                     $graph->edges->set($id, $edge);
                 }
             }
         }
         // set graph edge types as GraphCommons\Graph\Entity\EdgeTypes
         $graph->setEdgeTypes(new GraphEdgeTypes());
         if (!empty($g->edgeTypes)) {
             foreach ($g->edgeTypes as $_) {
                 $id = trim($_->id);
                 if ($id != '') {
                     $nodeType = (new GraphEdgeType($graph))->setId($id)->setName($_->name)->setNameAlias($_->name_alias)->setDescription($_->description)->setWeighted($_->weighted)->setDirected($_->directed)->setDurational($_->durational)->setColor($_->color)->setProperties($_->properties);
                     $graph->edgeTypes->set($id, $nodeType);
                 }
             }
         }
     }
     // set/update each entity's original object
     if (isset($graph->nodes)) {
         foreach ($graph->nodes as $id => $node) {
             // set/update node type
             $nodeType = $graph->nodeTypes->get($node->typeId);
             if (!empty($nodeType)) {
                 $node->setType($nodeType);
             }
         }
     }
     if (isset($graph->edges)) {
         foreach ($graph->edges as $id => $edge) {
             // set/update edge type
             $edgeType = $graph->edgeTypes->get($edge->typeId);
             if (!empty($edgeType)) {
                 $edge->setType($edgeType);
             }
             // set/update edge type
             $user = $graph->users->get($edge->userId);
             if (!empty($user)) {
                 $edge->setUser($user);
             }
             // set/update from node
             $fromNode = $graph->nodes->get($edge->from);
             if (!empty($fromNode)) {
                 $edge->setFromNode($fromNode);
             }
             // set/update to node
             $toNode = $graph->nodes->get($edge->to);
             if (!empty($toNode)) {
                 $edge->setToNode($toNode);
             }
         }
     }
     return $graph;
 }