Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Talk:Web services

From MoodleDocs

general remarks about OUTPUT of operations:

Is true of false informative enough ? Should the API have some sort of "last_error" function giving back more details such as "non existing course, non existing user, duplicate entry ...) Shall we consider that affecting a role that already exist or removing role that do not exist as an error (output=false) or not (output=true)

yep, agree, I'd result always one well defined $result object, with his status, error code and error msg (and perhaps, the whole original WS request encapsulated for easier debugging).
Eloy Lafuente (stronk7) 19:55, 21 December 2007 (CST)

I agree but throught the WS we need to be be carefull with the feedback we give to errors, due to security issues. --Ludo (Marc Alier) 14:14, 22 December 2007 (CST)

some WS to be able to... build courses ?

Perhpas it would be a great idea to start thinking about some WS functionalities like this:

  • add_course, delete_course, reset_course
  • add_section, delete_section, show_section, hide_section
  • add_activity, delete_activity, show_activity, hide_activity

Apart from the WS utility itself: automated creation of courses... it would help (or force, as we prefer), to better encapsulate course/section/modules internals, 100% isolating the creation and configuration from the frontend (forms, WS...). It implies some decisions, like upwards compatibility of old modules (although I think it can be maintained)... and so on, you know.

Just one idea to analyse. But with benefits in the end, IMO. Eloy Lafuente (stronk7) 20:02, 21 December 2007 (CST)

I do agree with this ; this would also allow creation of specific courses, customized for some users, depending of their "performances" in external evaluations methods ; when the ePortfolio API will be finalized in Moodle core's, accessing the portfolio of any user would be needed. Patrick Pollet 04:21, 30 December 2007 (CST)

the problem of ID of entity to fetch:

In the list of API calls defined in this page, Moodle entity to process (user,course,grade,event ...) is identified by an ID, that is implicitly the Moodle's internal id field used in the database. This raises a problem since it is very likely that in the "external SIS" talking to Moodle across the Web Service, the entity will be identified by another attribute such as an idNumber (user,course), a short name (course) or even an username (login of user).

So either we must provide :

  • extra API calls to convert external identifiers to Moodle's internal id, such as user_id_from_idnumber, user_id_from_username, course_id_from_shortname ..., at the cost of extra calls before the real one ; three calls would be needed to enrol student "CS2121212", to course "JAVA_101".
  • extra API functions such as delete_user_byusername, get_course_by_idnumber , enrol_student_byidnumber_tocourse_byshortname ....
  • or add parameters to the current API calls specifiying what identifier we are using such as delete_user(id,idField) with idField being a string that could be "id","idnumber","username","email" ... or enrol_student(sid,"idnumber",cid,"shortname") . This is the approach in the current SOAP implementation (with some calls of the previous type (get_user_byusername()...)

Patrick Pollet 04:21, 30 December 2007 (CST)

output of operations: adding URLs?

In addition, I suggest to return the full URL towards every Moodle entity, either added or got.

Today, in my uPortal installation, I request for Moodle database and display a list of courses in which the connected user is enrolled. Of course I provide links to these courses so that he can directly access. In addition I display a list of the last changes in these courses, again with links to the resources/activities.

If the URLs are returned by the WS then the calling service has nothing to know about Moodle URLs. Else it has to build every URL by aggregating Moodle alias + adequate PHP script + entity ID

Implementation feedback

[Feedback] Speaking as someone who will be using this API to integrate with another line of business application I would recommend the following changes.

The add_user method should really be a 'SetUser' ie it will create the record if it does not exist or update it it if it does. The ID that is passed into the method would be *our* primary key which Moodle would use to recognise the user record within Moodle. We would not normally need to know anything about the Moodle primary key.

One option to make the web services maintainable is to accept XML as a parameter and not a structure or custom object. That way you can define an XSD which will define required\optional parameters. Equally if you include a version number you can change the XML to add new features without having to redefine the web service signature itself (and hence clients will not have to recompile their code). So you may receive a SetUser call with XML V1.0 and another with XML V2.0 on the same webservice but from two different clients supporting different versions of the API.

The method *must* accept an array of users - it's a little trickier to set this up in the client code but is much more scalable (if there's some good sample code then this is easier anyway). The latency (round trip time) with web service calls is high so you want to do as much as you can in a single call. We have a customer who wants us to deploy Moodle to 40,000 users - we're not going to do that using individual calls.

Would it be possible to expand on the existing web service work rather than produce something completely new? We're investing a lot of effort with these services and we wouldn't like to have to re-do that work. [/Feedback]

Using web services to allow client side code such as js, Flash/Flex or java to communicate with Moodle

I understand these web services should also allow client side code to communicate with Moodle.

I imagined that web services used by client side code should be authenticated with a 'session key'. When the server outputs a page with such an object in it then a random session key string should be created and passed into the client side code through the html that embeds/outputs the object in a page. I think the session key should be associated with a user and probably a Moodle context. Then the context can be used within block related code or activity module related code to know when for example the client side code passes a log message back to Moodle or when it passes a grade back to Moodle that the grade is for such and such an activity. For web services for Flash I thought an appropriate way to do this would be to have an array of objects of session keys and there associated context/other data in the $SESSION object.

Config settings

This are the main switches / global config settings to control what's available:

  • WS Global switch:
    • Check for global$CFG->enablewebservices properly (outer layer).
  • WS Capability:
    • Create the 'moodle/site:use webservices' capability and check for it in medium layer globally (after auth). Default to admin role only.
  • WS Protocol/Function switches:
    • Create new setting $CFG->enabledwsprotocols, with list of enabled protocols (default to none) and check request against that (outer layer)
    • Create new setting $CFG->enabledwsfunctions, with list of enabled functions (default to none) and check request against that (on function invocation)
  • WS Function capabilities?? Not sure (overlay with normal capabilities). -1
  • Other restrictions (fixed list of users, IP, SSL required...)

Eloy Lafuente (stronk7) 08:44, 27 January 2009 (CST)

IP restriction

We'd like a feature to restrict web services to a list of specified IP addresses for additional security. On our services we just have like this:

$allowedaddresses=preg_split('/[,\s]+/',$CFG->privilegedserverips,-1,PREG_SPLIT_NO_EMPTY);
if(!in_array($_SERVER['REMOTE_ADDR'],$allowedaddresses,true)) {
   error('You are not permitted to access this page.');
}

(note I think REMOTE_ADDR may not be reliable on all systems? eh whatever)

so we use a comma-separated list of IP addresses that are permitted. Something similar would be good for this.

Maybe it should really go into the user section ie a way to restrict a specific user to given IPs? Of course ideally it would then support ranges/wildcards as well, etc, but then it becomes a lot of work instead of a simple option to the webservice stuff...

Sam marshall 08:52, 27 January 2009 (CST)

There is already a nice address_in_subnet function in lib/moodlelib.php, which gives you a flexible way to check IP addresses. Normally used in combination with getremoteaddr(), also in moodlelib.--Tim Hunt 20:40, 27 January 2009 (CST)

Why the Auth Plugin?

Just curious what I missed - what was the reason for implementing a web services auth plugin? I agree with what Eloy said in chat - the problem with this approach is that you'd probably want to apply any restrictions that might be implemented in the plugin to be applied to users with traditional authentication? --Dan Poltawski 01:32, 3 February 2009 (CST)

About the "how it works" section

Just two suggestions:

  • In point 1: instead of sending login + password I'd recommend sending login + hash(login and password) or something like that, just prevent sending plain password (and easily identificable). Assuming that SSL isn't a MUST, of course.
  • In point 10: together with the final response to the client with the results I'd recommend to send a renewed token, avoiding to use the same token all the time. That way, possibilities to explode a stolen token are really minimised.

Just in case those haven't been considered. Eloy Lafuente (stronk7) 22:13, 2 September 2009 (UTC)


Brainstorm for WS Roadmap

Current

user:

   create_users()
   delete_users()
   update_users()
   get_users_by_id() - returns a list of full user objects specified by user ids (only useful for site admin accounts)
   get_course_participants_by_id() - returns a list of full user objects in specific courses (that you can see)
   get_users_by_courseid() - returns some subset of full user objects from a course (perhaps by group or capability) 
   * get_completed_users_per_course()  ?
   * get_completed_courses_per_user()  ?
   * get_users (allows admin to search by various keys)
   

course:

   get_courses()
   create_courses() 
   * update_courses()  - including moving categories
   * delete_courses()
   * get_course_contents()  - including sections, activities etc 
   * get_recent_activity()  - also works for site course

group:

   create_groups()
   get_groups()
   get_course_groups()
   delete_groups()
   get_groupmembers()
   add_groupmembers()
   delete_groupmembers() 

roles:

   role_assign()
   role_unassign() 

enrol:

   get_enrolled_users() - get some minimal information about the users enrolled in a course (DEPRECATED)
   get_users_courses() - get list of course ids that a user is enrolled in (if you are allowed to see that)


enrol/manual:

   manual_enrol_users() 
   
   * manual_unenrol_users()
   * manual_update_enrolment()

enrol/cohort

   * cohort_enrol_cohort()
   * cohort_unenrol_cohort()

enrol/self

   * self_enrol_users()
   * self_unenrol_users()

webservice:

   get_siteinfo_parameters() 

message:

   send_instantmessages() 
   * get_instantmessages() - params for unread etc
   * create_contacts()
   * delete_contacts()

notes:

   create_notes()
   * delete_notes()
   

events:

   * create_event() - triggers an event

calendar:

   * create_events()
   * update_events()
   * delete_events()

private files:

   get_files()
   upload()  - DEPRECATED
   * create_files() - can also do folders via a flag
   * update_files()
   * delete_files()


categories:

   * create_categories()
   * delete_categories()
   * update_categories()
   * get_categories()
  

grades:

   * get_grades()  - for user, course, activity etc 
   * get_scales()  
   * get_outcomes()
   * update_grades()  - including feedback
   * create_grades()

ratings:

   * get_ratings()
   * create_ratings()
   * update_ratings()
   * delete_ratings()

comments:

   * get_comments()
   * create_comments()
   * update_comments()
   * delete_comments()

forum:

   * get_forums()
   * create_forums()
   * update_forums()
   * delete_forums()
   * get_discussions()
   * create_discussions()
   * update_discussions()
   * delete_discussions()
   * get_posts()
   * create_posts()
   * update_posts()
   * delete_posts()