How to contribute a web service function to core
- 1 Check the existing
- 2 Create a tracker issue
- 3 Function implementation
- 4 Peer-review
- 5 Integration
Check the existing
Create a tracker issue
Create a new feature issue in the tracker for your new web service function (it is allowed to create one issue for many function only if all functions are deeply related and that all core lib functions exist like for MDL-32662). The issue title should be the web service function name, and the issue description should indicate the specs. The following is an example.
This web service function will return assignments:
array of course ids - Default: empty array
array of capabilities - Default: empty array
array of [
course struct [id, fullname, shortname, timemodified]
array of assignment [id,name,timedue,grade,timemodified]
Keep the following in mind.
- The web service API is designed to be a clean set of functions with very little overlap. Each web service function should return minimal required information - sometimes ids are enough. We expect the client/external app to manage some local storage between calls. For example, an external app will always retrieve the courses information first. Any function down the app workflow, only needs to return course ids. The external app should already know course fullname, shortname...
- Avoid functions that are too specific - look for the most general possible case. For example, we don't need a set_this_field function when a generic update_object could do it. This is to avoid code duplication and long-term maintenance.
- Moodle contextids are generally internal to Moodle and are not used in the API. (This was discussed in this issue).
- web service function name should be: create, update, get, and delete. Avoid as much as possible add, set, remove...
- description/summary/textfields are always accompanied by a format field. On input: texts should be checked against PARAM_RAW. You must not use format_text(). On output textfields must use external_format_text(). Example:
//INPUT in xxx_parameters()
'inputtextaera' => new external_value(PARAM_RAW, 'some html param'),
'inputtextareaformat' => new external_format_value('inputtextarea', VALUE_DEFAULT), // VALUE_DEFAULT has for default format FORMAT_HTML. If not mention VALUE_REQUIRED is used.
//INPUT in xxx()
// no format_text() => just store it in the DB
$params['inputtextareaformat'] = external_validate_format($params['inputtextareaformat']);
//OUTPUT in xxx()
list($text, $textformat) = external_format_text($text, $textformatfromDB, $contextid, $component, $filearea, $itemid);
//OUTPUT in xxx_returns()
'text' => new external_value(PARAM_RAW, 'formatted text'),
'textformat' => new external_format_value('text'),
For short strings with no format component, they should go through external_format_string (since 3.0) on the way out. This is so that (e.g.) multi lang filters can be applied if appropriate.
// OUTPUT in xxx()
$str = external_format_string($str, $contextid);
//OUTPUT in xxx_returns()
'str' = new external_value(PARAM_TEXT, 'some text');
Add the watchers
Add the module maintainer as watcher on your issue. In most of the case, they will be the person to validate the proposal.
Link the issue
Link your issue to the Web service API Roadmap. Your issue should appear in the "has been marked as being related by:" section.
Agreement on the specs
Once the component leader agrees on the specs for a web service function, the web service function is placed as a subtask in the roadmap.
Implement the function according to the specs. The implementation must follow all of the below sections.
The code logic should be matching the logic in Moodle. In the best word you will only call a core lib function in Moodle and reproduce some required capabilities/context checkings (search for the core lib function in Moodle, you'll find the required checks).
However often a lib function doesn't exist and you need to reproduce the code logic from different scripts in Moodle. If you end up to create all this logic in your function, it's better to move all this new logic in a new lib function. Then create a tracker issue and indicates to update the scripts using your new generic lib function.
Note that if your web service function does something different from Moodle core, it may be either a feature missing from Moodle (must be implemented at the same time), either something that the function should not be doing (review your web service function specification).
The file structure is explained in the Web services API and the External function API. These are plugin example but they are easy to adapt to core. The easiest way to learn is to look at other functions in the Moodle code.
Capabilities and context checks
The capability checking should always match the capability checks used in the front-end. You must look for the file(s) where this capibility checks are used.
/// capability and context checking of core_group_create_groups
$context = get_context_instance(CONTEXT_COURSE, $group->courseid);
You also need to comment in the tracker issue about which file in core contains the permission/security checkings. Your web service function code must correspond 100% with Moodle permissions and behaviours - it is the most difficult part of the function implementation as the code logic could be in many different files. You will save reviewers a lot of time by letting them know which file to look at. Usually it's a form script + a page script in the UI, and sometimes in other places like admin pages.
Note: in services.php you'll find out that you can set a 'requiredcapabilities' settings for each web service function declaration. This is just a text help for the administrator. Moodle servers do not do any automaticcally check these capibilities. This is due to the fact that capability checks require a specific context, so you need to implement these checks in your external function.
Documentation for the client developer
written complete documentation in the xxx_params() and xxx_return() external description functions. The generated API documentation will only show to client developers information from these two functions and in the services.php file. Be concise about how to use the function.
Web service description functions
- set top level parameters as DEFAULT (don't use OPTIONAL)
- handled errors as described in this document
- DB write functions need to support transactions ($transaction = $DB->start_delegated_transaction(); / $transaction->allow_commit();)
Proper format and coding style
- ordered the functions: 1) xxx_params() 2) xxx() 3) xxx_returns() (so the integrator is not marked as the last history committer in Git for the functions)
- run the moodlecheck/codechecker on your modified file to check if you code match Moodle standard.
- follow Moodle coding style
You must write a Web Services Unit Test
Some tips when you create module functions:
- remember to check for conditional activity status when retrieving the module.
- there is a generic core_course_delete_module() already implemented for you.
- there are some function that help you to implement create/update_MODULE (work in progress: MDL-37083)
At various points, when a consumer is fetching and displaying information (a.k.a "viewing") for a moodle object (a course, an activity, a forum discussion...) it's needed to emulate such a "view" action because it may need to trigger different actions (an event, completion/grades recalculation, mark as read...). This was discussed @ MDL-49076 and it was agreed to:
- create a new xxx_view() core function providing the implementation of the view action for that given object. The implementation will include the event generation.
- the corresponding external function will be a simply a wrapper over the core function (adding all the external requirements, of course).
- the xxx_view() function implemented should be also used by the corresponding frontmost script normally in charge of that view action, replacing parts of it, now available in the function.
Some implementation examples:
- core_course_view_course: MDL-49453 (commits).
- core_notes_view_notes: MDL-49504 (commits).
- core_user_view_user_profile: MDL-49499 (commits).
- mod_forum_view_forum: MDL-49502 (commits).
- mod_forum_view_forum_discussion: MDL-49503 (commits).
You can now be peer-reviewed. Push your function in a Github branch named MDL-XXXX. Remember:
- only make one commit if you are the only contributor.
- do not modify lines not related to your issue. For example with Netbeans you can for example "Format" the entire file to make the code prettier. If the file contains some existing code, It is not a good idea because you would be "git blame" for all lines in the files. For reviewer, it's also much more difficult to know what was related to the MDL issue.
- fill up the test instruction of the MDL issue. It should be online, the phpunit command line to run the PHPunit test. A tester will run it after the integration process is finished. Only after this final test, the function will be available in Moodle releases.
Peer-reviews are done by the component maintainer (if you are the component maintainer, then you can pick your peer-reviewer). If there are no component maintainer (or if the component maintainer is not available) the peer-review should be assigned to moodle.com. Peer-reviewer can get help from the Peer reviewing checklist.
Integration / Moodle HQ development priority follows these rules:
- the web service functions required for the official Mobile app (generally very few);
- the web service functions for which a Git patch has been submitted;
- the most voted issues; and then
- other web service functions.