Context
I am building an custom api to receive data from a salesforce platform in order to synchronise job openings on our moodle platform.
The idea is simply: salesforce has a manual request that will send the job data to moodle, which will handle the data.
The issue
When I try to test the request (using Postman) I am getting an error that seems to come from the parameter validation. According to the message, my data is not having the property "data" that has a single structure (associative array) as value.
My custom plugin:
db/services.php
<?php
/**
* ...
*/
$functions = [
'local_jobboard_receive_salesforce_data' => [
'classname' => 'local_jobboard_external',
'methodname' => 'receive_salesforce_data',
'classpath' => 'local/jobboard/externallib.php',
'description' => 'Receives job data from Salesforce and saves it in the database.',
'type' => 'write',
'ajax' => false,
'capabilities' => '',
]
];
$services = [
'JobBoard API' => [
'functions' => ['local_jobboard_receive_salesforce_data'],
'restrictedusers' => 1,
'enabled' => 1,
'shortname' => 'jobboardapi'
]
];
externallib.php
<?php
/**
* ...
*/
use core\exception\invalid_parameter_exception;
use stdClass;
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/externallib.php");
class local_jobboard_external extends external_api
{
public static function receive_salesforce_data_parameters()
{
return new external_function_parameters(
array(
'data' => new external_single_structure(
array(
'title' => new external_value(PARAM_TEXT, 'Job title'),
'description' => new external_value(PARAM_RAW, 'Job description in markdown or HTML'),
'company' => new external_value(PARAM_TEXT, 'Company name'),
'location' => new external_value(PARAM_TEXT, 'Work location (Hybrid, Online, Office)', VALUE_OPTIONAL),
'deadline' => new external_value(PARAM_INT, 'Application deadline (Unix timestamp)'),
'type' => new external_value(PARAM_ALPHANUMEXT, 'Type (job or internship)'),
'note' => new external_value(PARAM_TEXT, 'HR or Account manager notes', VALUE_OPTIONAL),
'tags' => new external_value(PARAM_TEXT, 'Comma-separated skill tags'),
'targets' => new external_multiple_structure(new external_value(PARAM_TEXT, 'Target categories'))
)
)
)
);
}
public static function receive_salesforce_data($data)
{
global $DB;
$rawInput = $data;
error_log("[Salesforce API] Raw Input: " . $rawInput);
$decoded_data = json_decode($rawInput, true);
if (json_last_error() !== JSON_ERROR_NONE || !is_array($decoded_data)) {
error_log("[Salesforce API] Invalid JSON format.");
throw new invalid_parameter_exception('Invalid JSON format.');
}
if (!isset($decoded_data['data'])) {
$decoded_data = ['data' => $decoded_data];
}
$params = self::validate_parameters(self::receive_salesforce_data_parameters(), $decoded_data);
error_log("[Salesforce API] Parsed Params: " . json_encode($params));
// .. rest of the logic
}
public static function receive_salesforce_data_returns()
{
return new external_single_structure(
array(
'status' => new external_value(PARAM_TEXT, 'Success status'),
'message' => new external_value(PARAM_TEXT, 'Response message')
)
);
}
// other methods
}
My request header also has the content-type set to application/json.
Is there any reason for my request to fail? I am a bit at a loss here.
Thanks in advance!
Context
I am building an custom api to receive data from a salesforce platform in order to synchronise job openings on our moodle platform.
The idea is simply: salesforce has a manual request that will send the job data to moodle, which will handle the data.
The issue
When I try to test the request (using Postman) I am getting an error that seems to come from the parameter validation. According to the message, my data is not having the property "data" that has a single structure (associative array) as value.
My custom plugin:
db/services.php
<?php
/**
* ...
*/
$functions = [
'local_jobboard_receive_salesforce_data' => [
'classname' => 'local_jobboard_external',
'methodname' => 'receive_salesforce_data',
'classpath' => 'local/jobboard/externallib.php',
'description' => 'Receives job data from Salesforce and saves it in the database.',
'type' => 'write',
'ajax' => false,
'capabilities' => '',
]
];
$services = [
'JobBoard API' => [
'functions' => ['local_jobboard_receive_salesforce_data'],
'restrictedusers' => 1,
'enabled' => 1,
'shortname' => 'jobboardapi'
]
];
externallib.php
<?php
/**
* ...
*/
use core\exception\invalid_parameter_exception;
use stdClass;
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/externallib.php");
class local_jobboard_external extends external_api
{
public static function receive_salesforce_data_parameters()
{
return new external_function_parameters(
array(
'data' => new external_single_structure(
array(
'title' => new external_value(PARAM_TEXT, 'Job title'),
'description' => new external_value(PARAM_RAW, 'Job description in markdown or HTML'),
'company' => new external_value(PARAM_TEXT, 'Company name'),
'location' => new external_value(PARAM_TEXT, 'Work location (Hybrid, Online, Office)', VALUE_OPTIONAL),
'deadline' => new external_value(PARAM_INT, 'Application deadline (Unix timestamp)'),
'type' => new external_value(PARAM_ALPHANUMEXT, 'Type (job or internship)'),
'note' => new external_value(PARAM_TEXT, 'HR or Account manager notes', VALUE_OPTIONAL),
'tags' => new external_value(PARAM_TEXT, 'Comma-separated skill tags'),
'targets' => new external_multiple_structure(new external_value(PARAM_TEXT, 'Target categories'))
)
)
)
);
}
public static function receive_salesforce_data($data)
{
global $DB;
$rawInput = $data;
error_log("[Salesforce API] Raw Input: " . $rawInput);
$decoded_data = json_decode($rawInput, true);
if (json_last_error() !== JSON_ERROR_NONE || !is_array($decoded_data)) {
error_log("[Salesforce API] Invalid JSON format.");
throw new invalid_parameter_exception('Invalid JSON format.');
}
if (!isset($decoded_data['data'])) {
$decoded_data = ['data' => $decoded_data];
}
$params = self::validate_parameters(self::receive_salesforce_data_parameters(), $decoded_data);
error_log("[Salesforce API] Parsed Params: " . json_encode($params));
// .. rest of the logic
}
public static function receive_salesforce_data_returns()
{
return new external_single_structure(
array(
'status' => new external_value(PARAM_TEXT, 'Success status'),
'message' => new external_value(PARAM_TEXT, 'Response message')
)
);
}
// other methods
}
My request header also has the content-type set to application/json.
Is there any reason for my request to fail? I am a bit at a loss here.
Thanks in advance!
Share Improve this question edited Mar 20 at 7:20 VLAZ 29.1k9 gold badges63 silver badges84 bronze badges asked Mar 19 at 16:12 BasileBasile 1721 silver badge14 bronze badges 2 |1 Answer
Reset to default 0Moodle rest webservice calls usually expect all of the data to be passed as URL parameters, it doesn't look at the body of any request.
So, it would need to look something like:
http://localhost/webservice/rest/server.php?wstoken=xxx&wsfunction=local_jobsboard_recieve_salesforce_data&wsmoodlerestoformat=json&data['title']=Software%20Engineer&data['description']=We%20are%20looking%20for%20a
etc.
Note that wsmoodlerestformat is there to specify the response format, not the format of the data accepted.
There are a couple of 3rd-party plugins out there that add new webservice protocols that allow the content to be included as JSON in the body of the request:
https://moodle./plugins/webservice_restful - officially supports Moodle 4.4 (so not quite the latest Moodle 4.5, at the time of writing, but should still work)
https://moodle./plugins/webservice_restjson - only supports Moodle 2.9, has not been updated in 9 years (at the time of writing), so may have problems with recent versions of Moodle
data
. Have you tried wrapping that in one additional array: 3v4l./mOk52 – Chris Haas Commented Mar 19 at 17:49$decoded_data = ["data" => [...]]
. but maybe i'm overlooking something? 3v4l./IbOX2 – Basile Commented Mar 19 at 21:45