Published
Wednesday, February 16, 2011 - 12:11
Written by

This new API is the recommended method to Create, Get, Delete or Update any CiviCRM data from your code or an external system. It is much more coherent and easier to use than the api v2.

 

As of the civicrm 3.4/4 and as already available for your viewing pleasure on sandbox.civicrm.org (login/password demo/demo), we have developed an API explorer and code generator that is shipped with civicrm and will let you use interactively the api directly on your own data.

 

This tool is using the ajax version and you can either type the url for the API you want, press enter and get the result of your request displayed on the grey box, or use the drop down lists.

This explorer exposes the two main parameters of the API:

  • The entity: what you want to manipulate (a contact, a tag, a group, a relationship...). They are now 39 different type of entities, and more or less all what is present on civicrm.
  • The action: get (to retrieve a list or a single entity), create (to create or update if you provide the id), delete, update and getFields (that provide the list of fields of this entity, including the custom fields)

 

Beside showing you the result of each api call in the grey box (by default formated as json, but can also be xml), it also generate the code for the different ways of using the API:

  • The url for the ajax call (the one used to retrieve the result displayed on the grey box)
  • The url for the REST api (so you can call the API from an external server)
  • the smarty code (so you can directly add extra information, like the list of membership in any page, like the contact summary)
  • the php call from your own module
  • the jquery call, so you can add ajax features

 

The main difference with the api v2 is that now the entity+action are much more visible instead of being implied in the name of the function, and the recommended way of calling an api in php is now:

 

$result =civicrm_api ($entity,$action,$params);

 

eg. to retrieve the students (by default limited to 25)

$params = array ('contact_type'=>'Individual', contact_subtype => 'student', version => 3);

$result = civicrm_api('contact','get',$params);

(another improvment on the api v2, params is by value so you can call civicrm_api('contact','get',array( ...));

result always contain "is_error" (0 if you didn't have any problem), count (the number of results returned), and results (that contains the list of entities).

 

This api v3 can run in parallel with version 2, that we are going to maintain on 3.4/4. This being said, we are recommending you to migrate your existing modules to the api v3, and certrainely to start any new development with it. On the API explorer tool, you can choose what version of the api you want, so you can compare the result of the two and help you on the migration from your existing code.

 

If you choose the the action create on the API explorer, it won't directly generate the call as you would get an error about a missing param (obviously, you need to provide some values when you create an entity) but will show you all the available fields for the entity you are trying to create. Click on it and you get the field, fill it and press enter. Voila, if you have is_error=0 in the grey box, it means that you have created it properly.

 

It's so fast that I have started using it as a poweradmin tool, for instance to create a list of tags or groups.

 

if you get an error, the error message not, you can simply alter the url and see what parameters are needed (in theory, the ones in bold are mandatory, but isn't 100% correct now). In any case, this discovering process by trial and error is much faster and enjoyable than having to alter your php code and re-run. once you found the right parameters for your action, you can copy paste the code and use it in your application.

 

Or you can browse the documentation and take a look in the examples directory to get a feel for them

 

Extending the api

It should be noted that it's extremely easy to extend the api if you want to add some funky features: add a Magic.php file under api/v3, create a function civicrm_magic_getpony and voila, you have civicrm_api ("magic","getpony"), the smarty, the ajax, the REST, and it's also directly usable from the api explorer at /civicrm/ajax/doc

 

What's still not perfect

We want to push the standardisation further and cover 100% of the entities with at least create get and delete actions.

 

We also want to be more systematic on the naming of the parameters and always have "id" as a valid parameter for any entity for get, modify, delete. Right now, we still have sometimes entity_id (eg contribution_id), or entity (tag).

We would very much appreciate your help to finish this, to have the v3 as coherent and predictable as possible.

 

As soon as we get than done, we get the modify action available (and working) for all the entities (the code is there already and does a get+merge the existing params and the ones from the database and save). However to have it working, it needs that each entity get and create api handles the id parameter.

 

When we started that v3 project with the API team, I doubt that any of us had the vision of such a complete change (nor the size of the task). I'm proud to have been part of that group, and I'd like to thanks specifically Erik & Eileen for their hard work and enlighting discussions.

 

As for the future, we'd like first to finish that api v3, and we have plenty of new ideas (being able to chain the api calls within the same ajax/REST call, being able to have hooks on the apis...) that are going to be much more easier to add now that we have a sound foundation with this version.

Filed under

Comments

This looks fantastic, and I have a question/suggestion:

Because adding/updating a contact almost always goes hand-in-hand with editing their location, and because create and update are so similar, for my own personal use I ended up creating a wrapper function for the contact/location APIs (all v2, of course) which given contact and location data will:

  • search for an existing contact using dedupe rules
  • update existing contact if they do exist
  • add a contact if they don't exist
  • add new location record if they don't already have one
  • update their existing location if they do have one
  • return the contact id

Having a single function take care of this very common set of tasks is just so darn convenient, and I wonder if this sort of thing is already handled by v3 or if such a wrapper could be included in the API. I'd be happy to write some code for it if you think theres a place for such a thing.

It does look fantastic.  Just for those that are newer to Civi (i.e. me :)) it took me a while to find that the api is at civicrm/ajax/doc.  I read the blog and my RSS reader didn't show me that there was a video to go along with it, so took me a while to work this out :)  If I want to have that API explorer on my own installs, do I need to install from SVN?

 

Also, I had exactly the same requirement as colemanw and went down the same path of writing a "wrapper"... I tend to think that given that you can create an email address with the contact create call, and that you can add an email using the location part of the API, that you should be able to create a phone number and address with the initial contact create call as well, to remain consistent.

 

I did notice that the email passed in via contact create always creates it as a home email as far as I could work out, so it would be nice if you could get the create to respect location_type_id as well...

Hi,

Well, that civicrm/ajax/doc is brand new and has landed in svn trunk only two days ago, so quite normal that you don't know it ;). The trunk contains the code for 3.4 and the alpha version will be announced soon. You can already install from the svn and your are encouraged to see what is new, and what we have broken ;)

Right now, we are moving away from complicated apis that manipulate everything in one call and try to split the api is more managable bits.

So to create a contact with a phone and address and email, you'd call contact_create, email_create, phone_create and address_create. The email_create will have a type so you can say it's the home/billing/... email

 

BTW, you can change the default type of the locations (by default home, but you can choose work)

...that I didn't know it :)

 

More just an FYI if you don't watch the video and head over to the Sandbox then it's pretty hard to find, so just wanted to mention the actual path for anyone else who didn't notice or watch the vid.

 

EDIT: Although I did notice that the link takes directly to the API Explorer, so not sure how I missed that.  Anyway, great work :)

The link wasn't to civicrm/ajax/doc when I published it and I updated it later.

 

Two possible explanations: either a wicked master plan to force you to watch the screencast, or that I published it way too late and didn't read before publishing.

And here I thought I was crazy for creating a wrapper.  Note however that you _can_ add address data via the contact API, it's just not intuitive.

/**
 * Add a contact to CiviCRM.
 *
 * This should be used instead of directly using the CiviCRM API.  It allows you to include the
 * primary address.
 *
 * @link  http://wiki.civicrm.org/confluence/display/CRMDOC/Contact+APIs#ContactAPIs-civicrmcontactadd%28%26%24params%29 
 * @param array $contact
 * @return array
 * 
 */
function dems_assets_contact_add($contact) {

  // Is there address data?
  $address_fields = array('street_address', 'postal_code', 'postal_code_suffix', 'city', 
    'state_province', 'state_province_name', 'state_province_id', 'country', 'country_name',
    'country_id');
  foreach ($address_fields as $address_field) {
    if (isset($contact[$address_field])) {
      $contact['address'][1][$address_field] = $contact[$address_field];
      unset($contact[$address_field]);
    }
  }

  // Merge address defaults in.
  if (isset($contact['address'][1])) {
    $contact['address'][1]['is_primary'] = TRUE;
    $contact['address'][1]['location_type_id'] = 1;
    $contact['address'][1]['country_id'] = 1228;
    if (isset($contact['address'][1]['state_province_name'])) {
      require_once('CRM/Core/PseudoConstant.php');
      $states = CRM_Core_PseudoConstant::stateProvince();
      $contact['address'][1]['state_province_id'] = array_search($contact['address'][1]['state_province_name'], $states);
      unset($contact['address'][1]['state_province_name'], $contact['address'][1]['state_province']);
    }
    elseif (isset($contact['address'][1]['state_province'])) {
      require_once('CRM/Core/PseudoConstant.php');
      $abbreviations = CRM_Core_PseudoConstant::stateProvinceAbbreviation();
      $contact['address'][1]['state_province_id'] = array_search($contact['address'][1]['state_province'], $abbreviations);
      unset($contact['address'][1]['state_province_name'], $contact['address'][1]['state_province']);
    }
  }

  civicrm_initialize();

  require_once 'api/v2/Contact.php';
  return civicrm_contact_add($contact);

}

Part of the problem is probably that this api is too smart for its own good.

By having simpier apis (contact_create, address_create) that do one and only one thing, we are going to be more predicatable to use.

For the ajax and REST, I'm tempted to add a way of chaining APIs calls in one single request (contact_create with these params, with the id returned and some extra param call address_create). To be continued...

API chaining supercedes the approach suggested here - check the wiki for links on Chaining

The location api was a nightmare to use. Right now, Erik is in the process of splitting it into simplier api (email, phone, address).

There is a need indeed for higher level APIs, right now, we focussed very much on having predictable and dump CRUD on a single entity, but definitely I see a point of having smarter ones.

Can you jump on the forum and we discuss what's the best place to add the ones you suggest ?

Sounds really great. I like the API explorer tool. A few thoughts though:

If you choose the the action create on the API explorer, it won't directly generate the call as you would get an error about a missing param (obviously, you need to provide some values when you create an entity) but will show you all the available fields for the entity you are trying to create. Click on it and you get the field, fill it and press enter. Voila, if you have is_error=0 in the grey box, it means that you have created it properly.

This is really unexpected behaviour.  If this is a documentation tool it shouldn't actually create data as I'm trying to figure out how the thing works. I think this feature will end up confusing a lot of people. 

 

I don't think the Smarty API is a good idea.  Having this kind of functionality on the presentation layer is bad programming.  Teaching themers to be bad programmers is not a good idea.  Especially since it's already possible to call PHP from within Smarty.  If you take that approach at least you can tell that you're doing something wrong. 

 

One nice thing about the API explorer is that it pretty much replaces the wiki documentation.  It would be good to move in any additional notes from the wiki that are not in the API explorer tool and then close the API wiki so as to prevent multiple diverging sets of documentation. 

being able to have hooks on the apis

Wouldn't that be redundant since there's already APIs for example when a contact gets CRUDed. If there are entities that don't already have such hooks I think it would be better to put them into core CiviCRM so that they are usable during regular operations as well as API operations.

Can't tell you how often I wanted to try to create an entity and had to try various variations of the params (location api, I'm looking at you). being able to quickly change the params and see what happen until you get what you wanted and no is_error=1 is very much the expected behaviour.

 

So for every create or delete action, expect data to be changed. In your own civicrm instance. We are all having fun between consenting adults, right ? ;) This being said, we might add a mode dry-run that won't execute the call.

 

A lot of CMS have some kind of fetch function to get data from the template as part of template language. In the FLOSS word, ez publish or spip have that at the only way to get data and display it on the "presentation" pages (not for the forms).

 

And fetching extra info in the template is not bad programming, the syntax is simple and that's IMO very readable, and having to write some php code to assign the variables to the smarty template won't be any better to avoid bad programmers practice.

And don't get me started about good practice on a CMS, having the php and html in the template mixed, php code you can store as a node content and so on are going to be nice topics for a rant on IRC one of these days ;)

 

As for the hooks, that's very much an idea so far, but one issue is that the hooks are on the pre/post, ie aren't called from the API. But you are right, might be better to put them in the DAO to be sure that's called everywhere.

I have already been playing with api/doc since Brussels, and I love it! And I am proud of all the work we have done in the v3 project in the little time we all have, and looking forward to improving the API's even further. Working on the address API now, hope to finish that early next week. Phone and Email will be the easier ones and follow straight after. Next one lined up for extensive testing: improving the XML in the REST interface. I have a draft version ready, but have pushed Address/Email/Phone API. As you all can see, enough work to keep us all happy.....would be wonderful if others want to take part too!

 

Just a note for anyone working on extending the API, the instructions above are slightly wrong (or perhaps updated/changed since Xavier wrote this article).  More up-to-date instructions are here:

http://wiki.civicrm.org/confluence/display/CRMDOC42/How+to+migrate+or+wr...

(The update to the above is: The function should be named civicrm_api3_magic_getpony rather than civicrm_magic_getpony)