Relationship between tables using RESTFul API

Hi, I would like to know how I can do to relate two tables with RESTFul API (it’s my first api).

I am creating a page that displays the information directly with the content that I can find into the API that I built. for example I have a table called “resource_content” and the other one is “body”. My relation is that the “body” could have only one “resource_content”, but “resource_content” can be in any “body”, so, my relate is one to much.

    <object class="ResourceContent" table="resource_content" extends="xPDOSimpleObject">
    <field key="titleBlock" dbtype="varchar" precision="255" phptype="string" null="false" default=""/>
	<field key="description" dbtype="varchar" precision="255" phptype="string" null="false" default=""/>
    <field key="block_id" dbtype="int" phptype="integer" null="false" default=""/>
    <field key="resource_id" dbtype="int" phptype="integer" null="false" default=""/>
    <field key="properties" dbtype="json" phptype="json" null="true"/>		
    <aggregate alias="CreatedBy" class="modUser" local="createdby" foreign="id" cardinality="one" owner="foreign"/>
    <aggregate alias="EditedBy" class="modUser" local="editedby" foreign="id" cardinality="one" owner="foreign"/>
</object>

<object class="Body" table="body" extends="xPDOSimpleObject">
    <field key="titleBlock" dbtype="varchar" precision="255" phptype="string" null="false" default=""/>
    <field key="description" dbtype="varchar" precision="255" phptype="string" null="false" default=""/>
    <field key="properties" dbtype="json" phptype="json" null="true"/>		
    <aggregate alias="CreatedBy" class="modUser" local="createdby" foreign="id" cardinality="one" owner="foreign"/>
    <aggregate alias="EditedBy" class="modUser" local="editedby" foreign="id" cardinality="one" owner="foreign"/>
</object>

With these objects, I created an class by every object

class MycontrollerResourceContent extends  modRestController {
  /** @var string $classKey The xPDO class to use */
  public $classKey = 'ResourceContent';
  /** @var string $defaultSortField The default field to sort by in the getList method */
  public $defaultSortField = 'id';
  /** @var string $defaultSortDirection The default direction to sort in the getList method */
  public $defaultSortDirection = 'ASC';
}

and the other class

class MycontrollerBody extends  modRestController {
  /** @var string $classKey The xPDO class to use */
  public $classKey = 'Body';
  /** @var string $defaultSortField The default field to sort by in the getList method */
  public $defaultSortField = 'id';
  /** @var string $defaultSortDirection The default direction to sort in the getList method */
  public $defaultSortDirection = 'ASC';
}

As I said before, I would like to relate both tables and make a request that when I call a body it comes with the resource or resources that have been assigned to it.

I don’t know if I made myself understood, I hope your help.

Thanks a lot

Maybe you can take a look at this thread where something similar is discussed:

In a nutshell: You have to override the functions prepareListObject or afterRead of the class modRestController.

To simplify the code, it would also help, if you defined the relationship between the two tables in your schema.

btw: If this is your complete schema, then you also have to define the fields createdby and editedby or the aggregate-relationships to modUser won’t work.

Thank halftrainedharry for taking a little time to reply to my post. I’m going to see the post that you recommend to me

halftrainedharry I saw the post and I have a question.
For example, I have two parameters, bodyId and resourceContentId, with these parameters I make a request https://xxx.xxx.x.x/modxMonster/rest/index.php?_rest=Resources/bodyId/resourceContentId
when I hit enter I need to see specific information. The question is, what is the best way to query a table with two parameters or using these field that I highlight in the picture.

One restriction is that in the query I can’t load the object to the other table

Hi there, not exactly your question, but we were struggling with the same and decided to go with URL parameters, so in your case, you’ll have something like Resources/bodyId?resourceContentId=value instead of Resources/bodyId/resourceContentId

And after that you need to add the get() implementation into your controller, below is an example of the method you’ll need
`
/**

  • Route GET requests
  • @return array
    */
    public function get() {
    $pk = $this->getProperty($this->primaryKeyField);
    if (empty($pk)) {
    return $this->getList();
    }
    // GET as many parameters you want
    $param1 = $_GET[‘param1’];
    if (empty($unitId)) {
    return $this->read($pk);
    }
    // Then use your parameters to query
    $object = $this->modx->getObject($this->classKey,[‘param1’ => $pk, ‘param1’ => $param1]);
    if (empty($object)) {
    return $this->failure($this->modx->lexicon(‘rest.err_obj_nf’,array(
    ‘class_key’ => $this->classKey,
    )));
    }
    $objectArray = $object->toArray();
    return $this->success(’’,$objectArray);
    }
    `

As I mentioned this is just a walk around but would also like to know the right way to implement it inside MODx to have it as Resources/bodyId/resourceContentId, which is a more ‘restful’ way, and later allows to build more robust APIs were you could mix inner objects with ID to traverse complex data models.

As @camicase82 said, the easiest way is to use URL parameters.

If you want to use a path like Resources/bodyId/resourceContentId then (as far as I can tell) you have to make some changes to the current Rest API.

  • Create a new class that extends the class modRestService and override the function getController so that it only takes the first part of the path into account when searching for the correct controller file.
class mymodRestService extends modRestService {
	protected function getController() {
		...
	} 
}
  • Change the file rest/index.php and load your newly created modRestService class (instead of the original one)
$rest = $modx->getService('myrest', 'mymodRestService', $base_path . 'path/to/file/', array(
   ...
));
  • In your controller in the get() function, you can access the requested path with $this->request->action. Parse the path into its components and then query the database accordingly.

An alternative could be (depending on your use case) not to use the MODx RESTful API at all, and instead use an extra like CustomRequest and create your “API endpoints” with resources.

1 Like