From ec34260d7b2e0dedae14530cc62a74eec5f5e296 Mon Sep 17 00:00:00 2001 From: baarkerlounger Date: Tue, 27 Jun 2017 23:01:19 +0100 Subject: [PATCH] API Readme (#1) * API Readme added to the main DB repo * Images --- Diveboard API 0.5.md | 3629 +++++++++++++++++++++++++++++++ public/img/creative_commons.png | Bin 0 -> 5281 bytes 2 files changed, 3629 insertions(+) create mode 100644 Diveboard API 0.5.md create mode 100644 public/img/creative_commons.png diff --git a/Diveboard API 0.5.md b/Diveboard API 0.5.md new file mode 100644 index 000000000..52e38a0dd --- /dev/null +++ b/Diveboard API 0.5.md @@ -0,0 +1,3629 @@ +![image alt text](/public/img/big_db_logo.png) + +PUBLIC API SPECIFICATION + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateVersionComment
0.1First version of the specification
April 25th 20120.2Updated the vanity_url, login_email and login_fb apis +Updated behavior of how species array is being stored in dives (s- replaces c-)
May 4th 20120.3Deprecate use of location_id and region_id in setters, replaced by location object and region object +you must update your code from object_id => id to object => {"id" => id}
October, 26th 20120.4Adding the new calls and parameters +apikey gets mandatory
December, 20th 20120.5Support for comma separated flavours
February, 5th 20140.6Updated version, deprecating attributes without _value/_unit
October 2nd 20140.7added wallet pictures
+ + +Table of content + +[[TOC]] + +# Terms of Use of the API + +(a) To make it possible for Materials of the Site to be accessible to new technologies, we have developed a series of Application Programming Interfaces ("APIs") that allow for the Materials to be retrieved by technologies using certain computer programming methodologies. The APIs are freely available for anyone to use. You must register with the Site by emailing ‘[support@diveboard.com](mailto:support@diveboard.com)’ to indicate your desire to use them, which will allow us to better support your use of the API. Upon registration, a unique API key code will be issued to you which you will need to be including in upcoming requests as described in the API Documentation. + +(b) If you develop a technology as a result of your use of the Site and the Materials on the Site, we encourage you to provide us with information about such technology. Sharing your success with us will help foster the Diveboard community by providing examples of success. We may choose to feature your story on the Site, or highlight your technology or product on the Site. + +(c) The Data published through Diveboard is licenced under Creative Common’s [is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License ](http://creativecommons.org/licenses/by-nc-nd/3.0/deed.en_US)![image alt text](/public/img/creative_commons.png) . Published data coming from Diveboard must link back to their location on Diveboard. Modification or corrections are only allowed through the APIs. If you are the original creator of a content you are free to push/pull/modify/delete such content. Diveboard may keep anonymized scientific data upon delete. + +(d) You also agree to comply with the licenses associated with the Materials you acquire from the Site. You also agree to pass on all license terms and attributions associated with the objects as required by the licenses associated with those Materials. + +(e) If you make use of our APIs, and should you wish to acquire all or major portions of the Materials from any individual content provider, you are required to contact that content provider directly. + +(f) We reserve the right to monitor usage of our APIs and to discontinue access to the Site by users of the APIs who are determined to be in violation of this Agreement. If you have registered with us, we will make an effort to notify you of any potential violations. In addition to monitoring, we may maintain records of API use and information about the requestor. + +# Introduction / Concepts + +## Getting in touch + +For any question about the API, please head to the #diveboard channel in irc.freenode.net. + +## General Idea + +The API was designed to be as generic as possible but still enabling complex and powerful actions. + +The API is very (maybe too) close to the actual DB model, and was mostly built as an abstraction layer handling permission and CRUD functions. You can list objects (dives, spots, … ) update them (if you have the rights to), create new object.... and even create nested objects within a single API call. + +## How to **test** + +For testing purposes, you may want to try and use our staging environment. Beware that this environment has always new features, but it should still be stable. + +Please do not make load testing with either environment without checking with us that it’s OK to do so ! + + + + + + + + + + + + + + + + + +
EnvironmentUsageURL
ProductionReal life environmenthttp://www.divaboard.com
StagingNext version testinghttp://stage.diveboard.com
+ + +# APIs + +## Presentation + +The APIs can be separated into 4 different kinds : + +1. administrative calls (login) + +2. object manipulation calls (read, create, update, delete dives, …) + +3. search (spots, …) + +4. file upload (profiles, pictures) + +All POST call should send the parameters as "Content-Type: multipart/form-data;" + +The ‘Walkthrough’ section gives examples on how to use the different APIs. + +For privacy issues, all calls should always be done over HTTPS. + +## Administrative functions + +### Login with Facebook + +#### Presentation + +This call logs in a user by checking fbtoken + fbid and issues a token which should be used to make further API calls. The issued token has a 1 month validity by default, but please refer to the expiration string to be sure of that. + +If the user is not registered on Diveboard, it will create an account linked with facebook authentication. + +#### URL + + + + + + + + + + +
HTTP methodURL
POST/api/login_fb
+ + +#### HTTP parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
fbidSTRINGMNUser's Facebook ID
fbtokenSTRINGMNUser's Facebook Token (as given by facebook)
apikeySTRINGMNthe application's API key
+ + +#### Output + +The body of the response is a JSON string, which contains a Hash. The attributes of this Hash are described in the table here. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
successBOOLEANMNfalse only if a big error
errorSTRING XXXONstring defining the error (only present if success==false)
error_tagStringONid of the error (only present if success==false) +This id should be provided when available to report bugs to Diveboard.
tokenStringMNstring with the authentication token to use
vanity_url_defined Deprecated
expirationSTRING +"2012-05-02T14:48:09Z"MNDate when the token expires - 1day (prevent all timezone craze)
idSTRINGMNShaken ID of the new user
units Deprecated
preferred_unitsUNITS ObjectMNUser preference about units
new_accountBOOLEANMNTrue if an account was created
userUSER ObjectMNThe User object rendered with a "private" flavour
+ + +### Login with Email/Password + +#### Presentation + +This call logs in a user by checking the email and password, and issues a token which should be used to make further API calls. The issued token has a 1 month validity by default, but please refer to the expiration string to be sure of that. + +If the user is not registered on Diveboard, it will create an account. In this case, the ‘vanity_url_defined’ attribute will be set to ‘true’ and you should make a call to ‘api/register_vanity_url’ to finish the registration process. + +#### URL + + + + + + + + + + +
HTTP methodURL
POST/api/login_email
+ + +#### HTTP parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
emailSTRINGMNUser's email
passwordSTRINGMNUser’s plaintext password
apikeySTRINGMNthe application's API key
+ + +#### *Output* + +The body of the response is a JSON string, which contains a Hash. The attributes of this Hash are described in the table here. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
successBOOLEANMNfalse only if a big error
errorSTRING XXXONstring defining the error (only present if success==false)
error_tagStringONid of the error (only present if success==false) +This id should be provided when available to report bugs to Diveboard.
units +DeprecatedJSON ObjectOY
preferred_unitsUNITS ObjectMNUser preference about units
tokenStringMNstring with the authentication token to use
expirationSTRING +"2012-05-02T14:48:09Z"MNDate when the token expires - 1day (prevent all timezone craze)
idSTRINGMNid of the user
new_accountBOOLEANMNTrue if an account was created
userUSER ObjectMNThe User object rendered with a "private" flavour
+ + + + +### Change a vanity_url + +#### Presentation + +This call will change a vanity url of a user. + +#### URL + + + + + + + + + + +
HTTP methodURL
POST/api/register_vanity_url
+ + +#### HTTP parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
tokenSTRINGMNUser’s authentication token
vanity_urlSTRINGMNChosen vanity URL
apikeySTRINGMNthe application's API key
+ + +#### Output + +The body of the response is a JSON string, which contains a Hash. The attributes of this Hash are described in the table here. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
successBOOLEANMNfalse only if a big error
errorSTRINGONstring defining the error (only present if success==false)
error_tagStringONid of the error (only present if success==false) +This id should be provided when available to report bugs to Diveboard.
+ + +## Object Manipulation + +### Presentation + +The set of API for object manipulation uses the same logic for all objects. It is based on JSON objects. + +When updating an object, some attributes may be rejected while others will be accepted. As a general rule, all the valid changes will be taken into account and applied, and only the invalid changes will be discarded. This mean that if you’re updating both the duration and the gears of a dive with a correct duration but an invalid gear, the change on duration will be applied but the change of gear will not be applied. The answer will notify you of the error on the gear update. + +To have the details of the objects that can be passed, please refer to the section "Objects". For a better understanding of how to manipulate these calls, you should have a look at the "Walkthrough" section. + +### URL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type of objectHTTP methodURL
userread : POST +create : POST +update : POST +delete : not available/api/V2/user +/api/V2/user/_id_
diveread : POST +create : POST +update : POST +delete : DELETE/api/V2/dive +/api/V2/dive/_id_
spotread : POST +create : POST +update : POST +delete : not available/api/V2/spot +/api/V2/spot/_id_
shopread : POST +create : POST +update : POST +delete : not available/api/V2/shop +/api/V2/shop/_id_
reviewread : POST +create : POST +update : POST +delete : DELETE/api/V2/review +/api/V2/review/_id_
notifread : POST +create : POST +update : POST +delete : DELETE/api/V2/notif +/api/V2/notif/_id_
+ + +### HTTP parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
flavourstringOYOne or several flavours separated by comma. This will command the level of detail for each object in the response. +e.g. "private,dive_profile"
argJSON STRING of OBJECT +or +JSON STRING of ARRAY of OBJECTMNJSON string describing the object to read, create, update or delete. +
auth_tokenSTRINGONauthentication string
apikeySTRINGMNAPI key
+ + +### Output + +The body of the response is a JSON string, which contains a Hash. The attributes of this Hash are described in the table here. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
successBOOLEANMNfalse only if a big error
errorARRAY of STRING +or..... +ARRAY of OBJECT ERRORONerrors can be reported even if success is true. For example, when updating an object, some attributes may be rejected while others will be accepted.
resultOBJECTOYonly if no error
error_tagStringONid of the error (only present if success==false) +This id should be provided when available to report bugs to Diveboard.
+ + +### Examples + +Here are a few simple example calls to read users detail and create a new dive. Please refer to the "Walkthrough" section for more complex examples. + +To get the details of a user : + + + + + + + + + + +
REQUESTcurl -X GET "http://www.diveboard.com/api/V2/user/48" -F "apikey=xxXXX6XXX6XxxxX6XXXX"
RESPONSE{"success":true,"error":[],"result":{"id":48,"vanity_url":"pascal","nickname":"Pascal", …................ }}
+ + +To get more detail for a user, use a different flavour (cf. the object section to get the list of values per parameter) : + + + + + + + + + + +
REQUESTcurl "http://www.diveboard.com/api/V2/user" +-F 'arg={"id":48}' +-F 'flavour=private' +-F 'auth_token=ip4rHSSD9/diOWR3szonh7ikbhl0k9g/UgMSTBfjb00=' +-F "apikey=xxXXX6XXX6XxxxX6XXXX"
RESPONSE{"success":true,"error":[],"result":{"flavour":"private","id":48,"vanity_url":"pascal","nickname":"Pascal", "pict":true, …................ }}
+ + +To create a new element, just send the data without specifying an id. You will get the id in the returned object detail : + + + + + + + + + + +
REQUESTcurl -s "http://l.dev.diveboard.com/api/V2/dive" +-F 'auth_token=UEEnVPDmErqKIKhI952vcQMnU1qbTQ/WxlXsnXUNBoY=' +-F "apikey=j9icv6zlgwq9" +-F 'arg={"user_id": 12885, "duration": 90, "maxdepth":40, "time_in": "2011-10-16T09:40:00Z", "spot": {"name":"Blue hole", "country_code":"MT","location":{"name":"Gozo"}, "region":{"name":"Mediterranean Sea"}}}'
RESPONSE{"success":true,"error":[],"result":{"class":"Dive","flavour":"public","id":31722,"shaken_id":"D6fQS5L","time_in":"2011-10-16T09:40:00Z","duration":90,"maxdepth":40.0,"user_id":12885,"spot_id":21481,"temp_surface":null,"temp_bottom":null,"privacy":0,"weights":null,"safetystops":null,"divetype":[],"favorite":null,"buddy":[],"visibility":null,"trip_name":null,"water":null,"altitude":0,"fullpermalink":"http://l.dev.diveboard.com//D6fQS5L","permalink":"//D6fQS5L","complete":true,"thumbnail_image_url":"http://l1.dev.diveboard.com/map_images/map_21481.jpg","thumbnail_profile_url":null,"guide":null,"shop_id":null,"notes":null,"public_notes":null,"diveshop":null,"current":null,"species":[],"gears":[],"user_gears":[],"dive_gears":[],"date":"2011-10-16","time":"09:40"},"user_authentified":true}
+ + +To update an element, you only need to provide the id of the element you wish to update and the parameters that need to be updated. The other details will not be changed. + + + + + + + + + + +
REQUESTcurl "http://www.diveboard.com/api/V2/dive" +-F "auth_token=ip4rHSSD9/diOWR3szonh7ikbhl0k9g/UgMSTBfjb00=" +-F "apikey=xxXXX6XXX6XxxxX6XXXX" +-F 'arg={"id":10306,"duration":120}'
RESPONSE{"success":true,"error":[],"result":{"class":"Dive","flavour":"public","id":10306,"time_in":"2011-10-16T09:40:00Z","duration":120,"maxdepth":"40.0","user_id":32,"spot_id":1843,"temp_surface":null,"temp_bottom":null,"privacy":0,"weights":null,"safetystops":null,"divetype":[],"favorite":null,"buddy":[],"visibility":null,"trip_name":null,"water":null,"altitude":0,"fullpermalink":"http://www.diveboard.com/duncan.farthing/10306","complete":false,"thumbnail_image_url":"http://www.diveboard.com/map_images/map_1.jpg","thumbnail_profile_url":null,"species":[],"guide":null,"shop_id":null,"notes":null,"public_notes":null,"diveshop":null,"gears":[],"user_gears":[],"dive_gears":[],"date":"2011-10-16","time":"09:40"}}
+ + + + +## Search + +### Spots + +#### Presentation + +This API will let you search spot base from a lat/long OR a name. + +If an auth_token and apikey is passed, user will be logged and will access his private spots (if any) + +#### URL + + + + + + + + + + +
HTTP methodURL
GET/POST/api/search/spot
+ + +#### HTTP parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
qSTRINGONname to search
latFLOATONlatitude in degrees
lngFLOATONlongitude in degrees
apikeySTRINGMNApi key
auth_tokenSTRINGONuser auth token
+ + +#### Output + +The body of the response is a JSON HASH, which contains an ARRAY of maximum 50 answers. The attributes of this Hash are described in the table here. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
sucessBOOLEANMNtrue/false
dataJSON ARRAY (see below)MNarray of spot data
errorSTRINGOYerror explained
+ + +data : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
nameSTRINGMNa formatted name of the spot i.e. "White River (Greece - Cyprus)"
idINTEGERMNspot ID
dataSPOT object, public flavourMNSPOT Object, public flavour
+ + +### Species + +#### Presentation + +This API will let you search **species** base for a name or search for family of a given id( ancestors...). + +On species search only species are returned (no other taxonrank) + +IDs have 2 formats : s-12345 for scientific names and c-12345 for common names … they are STRINGS + +#### URL + + + + + + + + + + +
HTTP methodURL
POST/api/fishsearch_extended
+ + +#### HTTP parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
nameSTRINGONname to search
idSTRINGONthe id of a base species (s-xxxx or c-xxxx)
scopeSTRINGON"children", "siblings", "ancestors" for a given id - only works if id is given
page_sizeIntegerONnumber of results per page
pageINTEGERONpage number
apikeySTRINGMNApi key
+ + +#### Output + +The body of the response is a JSON HASH, which contains an ARRAY of maximum 50 answers. The attributes of this Hash are described in the table here. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
sucessBOOLEANMNtrue/false
resultJSON ARRAY of SPECIESMNarray of spot data
paginateJSON paginate objectMN"paginate":{"next":null,"previous":null,"total":5,"total_pages":1,"current_page":1}
errorSTRINGOYerror explained
+ + +data : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
idSTRINGMN"s-13124" or "c-124214"
snameSTRINGMNscientific name
cnameSTRING ARRAYMYlist of common names
preferred_nameSTRINGMYPreferred common name
pictureSTRINGMYlink to a picture
bioSTRINGMYBiological info from EOL
rankSTRINGMNtaxon rank
categorySTRINGMNwhat family the fish belong to
dataSPOT object, public flavourMNSPOT Object, public flavour
+ + +## Uploading files + +### Profile upload + +#### Presentation + +This API needs to be used before assigning or creating a dive with a given profile. As of version 0.1, it supports UDCF and DL7 file formats. + +#### URL + + + + + + + + + + +
HTTP methodURL
POST/api/upload_profile
+ + +#### HTTP parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
tokenSTRINGMNtoken for the user
filenameBINARYMNcontent of the file
apikeySTRINGMNApi key
+ + +#### Output + +The body of the response is a JSON string, which contains a Hash. The attributes of this Hash are described in the table here. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
successBOOLEANMN
errorSTRINGON
nbdivesINTEGERMNnumber of dives found in the uploaded file
dive_summaryARRAY of HASHMNFor each dive found in the file, a summary of the dive is reported in a hash containing the following keys : +- number: 0 : the number of the dive in the file (if file has many dives) +- date: "2010-07-28" : date of the dive as in the file +- time: "21:18" : the time in HH:MM +- duration: 77 : in minutes +- max_depth: 7.9 : in meters +- maxtemp: 25 : in celsius +- mintemp: 2 : in celsius +- newdive: true : does it look like a new dive or a profile the user already has uploaded ?
fileidINTEGERMNID of the uploaded file
+ + + + +### Picture upload + +#### Presentation + + ‘TODO XXX’ + +#### URL + + + + + + + + + + +
HTTP methodURL
POST/api/picture/upload
+ + +#### HTTP parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
qqfile
+ + +#### Output + +The body of the response is a JSON string, which contains a Hash. The attributes of this Hash are described in the table here. + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
+ + +# WALKTHROUGH + +## Logging in + + + + + + + + + + + +
Example to log in a user with his facebook ID and facebook token
curl -s "http://stage.diveboard.com/api/login_fb" +-F "fbid=100004637132223" +-F "fbtoken=AAABzYDF4nt0BAL1e0gF86RRV4xoRu2rZAmXxJerM4IJLbXLZBNm2KiVXYD7ZBakiNgreUP5yPDMwqpYIhKnoNnIK" +-F "apikey=hwkzq4rhw9lq"
{"success":true,"token":"wtV6sxKrMdXXBV+dVrqhJs936KKrq0TQBw2toWjM+Lk=","expiration":"2012-11-26T19:57:44Z","vanity_url_defined":false,"units":{"distance":"Km","weight":"Kg","temperature":"C","pressure":"bar"},"id":"U3T7iSQ"}
+ + +## Reading an object + +To get an object with a given flavour from an id, you need to call the given API and pass as argument only the ‘id’ value in the ‘arg’ hash. + + + + + + + + + + + +
Example to get the basic details for a user
curl -s "http://stage.diveboard.com/api/V2/user/U3T7iSQ" +-F "apikey=hwkzq4rhw9lq"
{"success":true,"error":[],"result":{"class":"User","flavour":"public","id":12850,"shaken_id":"U3T7iSQ","vanity_url":null,"qualifications":{},"picture":"http://graph.facebook.com/100004637132223/picture?type=normal","picture_small":"http://graph.facebook.com/100004637132223/picture?type=square","picture_large":"http://graph.facebook.com/100004637132223/picture?type=large","full_permalink":"http://stage.diveboard.com/","total_nb_dives":0,"public_nb_dives":0,"public_dive_ids":[],"nickname":"David Narayanansen"},"user_authentified":false}
+ + +## Creating an object + +Creating an object is similar to updating an object.... but since you don’t know what ‘id’ the object will get, then just don’t supply it ! If everything went correctly, you’ll get the JSON of the object in the response, and you may then get the attributed ‘id’ for further updates. + + + + + + + + + + + +
Example to create a new dive
curl -s "http://stage.diveboard.com/api/V2/dive" +-F 'auth_token=wtV6sxKrMdXXBV+dVrqhJs936KKrq0TQBw2toWjM+Lk=' +-F "apikey=hwkzq4rhw9lq" +-F 'arg={"user_id": "U3T7iSQ", "duration": 90, "maxdepth":40, "time_in": "2011-10-16T09:40:00Z", "spot":{"id":1843}}'
{"success":true,"error":[],"result":{"class":"Dive","flavour":"public","id":31671,"shaken_id":"D3eyz9U","time_in":"2011-10-16T09:40:00Z","duration":90,"maxdepth":40.0,"user_id":12850,"spot_id":1843,"temp_surface":null,"temp_bottom":null,"privacy":0,"weights":null,"safetystops":null,"divetype":[],"favorite":null,"buddy":[],"visibility":null,"trip_name":null,"water":null,"altitude":0,"fullpermalink":"http://stage.diveboard.com//D3eyz9U","permalink":"//D3eyz9U","complete":true,"thumbnail_image_url":"http://stage.diveboard.com/map_images/map_1843.jpg","thumbnail_profile_url":null,"guide":null,"shop_id":null,"notes":null,"public_notes":null,"diveshop":null,"current":null,"species":[],"gears":[],"user_gears":[],"dive_gears":[],"date":"2011-10-16","time":"09:40"},"user_authentified":true}
+ + +## Updating part of an object + +To update some attributes from an object, you need to pass the ‘id’ of the object and then include in the ‘arg’ hash only the attributes you wish to modify. Please note that if you include one attribute with a ‘null’ value, we will try to overwrite that attribute in the database to null. So be careful to send only the attributes you wish to update, or make sure you send the exact same value. + + + + + + + + + + + +
Example to update the nickname of a user
curl -s "http://stage.diveboard.com/api/V2/user" +-F 'arg={"id":"12850", "nickname":"New Nick"}' +-F 'auth_token=wtV6sxKrMdXXBV+dVrqhJs936KKrq0TQBw2toWjM+Lk=' +-F "apikey=hwkzq4rhw9lq"
{"success":true,"error":[],"result":{"class":"User","flavour":"public","id":12850,"shaken_id":"U3T7iSQ","vanity_url":null,"qualifications":{},"picture":"http://graph.facebook.com/100004637132223/picture?type=normal","picture_small":"http://graph.facebook.com/100004637132223/picture?type=square","picture_large":"http://graph.facebook.com/100004637132223/picture?type=large","full_permalink":"http://stage.diveboard.com/","total_nb_dives":0,"public_nb_dives":0,"public_dive_ids":[],"nickname":"New Nick"},"user_authentified":true}
+ + + + + + + + + + + + +
Example to update both the duration and the depth on a dive
curl -s "http://stage.diveboard.com/api/V2/dive" +-F 'auth_token=wtV6sxKrMdXXBV+dVrqhJs936KKrq0TQBw2toWjM+Lk=' +-F "apikey=hwkzq4rhw9lq" +-F 'arg={"id": "31671", "duration": 50, "maxdepth":50}'
{"success":true,"error":[],"result":{"class":"Dive","flavour":"public","id":31671,"shaken_id":"D3eyz9U","time_in":"2011-10-16T09:40:00Z","duration":50,"maxdepth":50.0,"user_id":12850,"spot_id":1843,"temp_surface":null,"temp_bottom":null,"privacy":0,"weights":null,"safetystops":null,"divetype":[],"favorite":null,"buddy":[],"visibility":null,"trip_name":null,"water":null,"altitude":0,"fullpermalink":"http://stage.diveboard.com//D3eyz9U","permalink":"//D3eyz9U","complete":true,"thumbnail_image_url":"http://stage.diveboard.com/map_images/map_1843.jpg","thumbnail_profile_url":null,"guide":null,"shop_id":null,"notes":null,"public_notes":null,"diveshop":null,"current":null,"species":[],"gears":[],"user_gears":[],"dive_gears":[],"date":"2011-10-16","time":"09:40"},"user_authentified":true}
+ + + + + + + + + + + + +
Example to add a dive profile to a dive
curl -s "http://stage.diveboard.com/api/V2/dive" +-F 'auth_token=z61mYD1bUa7xCJBAfOqcBmy8I/rGGpkMKrQS5dOaHio=' +-F "apikey=76soje9nvcne" +-F 'flavour=public_with_profile' +-F 'arg={"id": "31678", "raw_profile":[{"seconds":0, "depth":0}, {"seconds":30, "depth":3}, {"seconds":60, "depth":5}, {"seconds":90, "depth":10}, {"seconds":2900, "depth":10}, {"seconds":3000, "depth":0} ]}'
{"success":true,"error":[],"result":{"class":"Dive","flavour":"public_with_profile","id":31678,"shaken_id":"D44ZZwl","time_in":"2011-10-16T09:40:00Z","duration":50,"maxdepth":50.0,"user_id":12855,"spot_id":1843,"temp_surface":null,"temp_bottom":null,"privacy":0,"weights":null,"safetystops":null,"divetype":[],"favorite":null,"buddy":[],"visibility":null,"trip_name":null,"water":null,"altitude":0,"fullpermalink":"http://stage.diveboard.com//D44ZZwl","permalink":"//D44ZZwl","complete":true,"thumbnail_image_url":"http://stage.diveboard.com/map_images/map_1843.jpg","thumbnail_profile_url":"http://stage.diveboard.com//31678/profile.png?g=small_or&u=m","guide":null,"shop_id":null,"notes":null,"public_notes":null,"diveshop":null,"current":null,"species":[],"gears":[],"user_gears":[],"dive_gears":[],"date":"2011-10-16","time":"09:40","raw_profile":[{"class":"ProfileData","flavour":"public","seconds":0,"depth":0.0,"current_water_temperature":null,"main_cylinder_pressure":null,"heart_beats":null,"deco_violation":false,"deco_start":false,"ascent_violation":false,"bookmark":false,"surface_event":false},{"class":"ProfileData","flavour":"public","seconds":30,"depth":3.0,"current_water_temperature":null,"main_cylinder_pressure":null,"heart_beats":null,"deco_violation":false,"deco_start":false,"ascent_violation":false,"bookmark":false,"surface_event":false},{"class":"ProfileData","flavour":"public","seconds":60,"depth":5.0,"current_water_temperature":null,"main_cylinder_pressure":null,"heart_beats":null,"deco_violation":false,"deco_start":false,"ascent_violation":false,"bookmark":false,"surface_event":false},{"class":"ProfileData","flavour":"public","seconds":90,"depth":10.0,"current_water_temperature":null,"main_cylinder_pressure":null,"heart_beats":null,"deco_violation":false,"deco_start":false,"ascent_violation":false,"bookmark":false,"surface_event":false},{"class":"ProfileData","flavour":"public","seconds":2900,"depth":10.0,"current_water_temperature":null,"main_cylinder_pressure":null,"heart_beats":null,"deco_violation":false,"deco_start":false,"ascent_violation":false,"bookmark":false,"surface_event":false},{"class":"ProfileData","flavour":"public","seconds":3000,"depth":0.0,"current_water_temperature":null,"main_cylinder_pressure":null,"heart_beats":null,"deco_violation":false,"deco_start":false,"ascent_violation":false,"bookmark":false,"surface_event":false}]},"user_authentified":true}
+ + +## Adding or removing a pre-existing element in a list + +As for the standard attribute update, you need to pass the ‘id’ of the object and then include in the ‘arg’ hash only the attributes you wish to modify. Now, for lists, you need to supply the whole list of elements. For existing objects, you don’t need to send back the whole details of the sub-objects : just their ‘id’ is sufficient. This means for example that to add an element you need to supply the previous list plus the new element. + + + + + + + + + + + +
Example to add a gear to a dive
curl -s "http://stage.diveboard.com/api/V2/user" +-F 'auth_token=wtV6sxKrMdXXBV+dVrqhJs936KKrq0TQBw2toWjM+Lk=' +-F 'flavour=private' +-F "apikey=hwkzq4rhw9lq" +-F 'arg={"id":"12850", "user_gears": [{"category":"Computer", "model":"Vyper", "manufacturer":"Suunto"}]}'
{"success":true,"error":[],"result":{"class":"User","flavour":"private","id":12850,"shaken_id":"U3T7iSQ","vanity_url":null,"qualifications":{},"picture":"http://graph.facebook.com/100004637132223/picture?type=normal","picture_small":"http://graph.facebook.com/100004637132223/picture?type=square","picture_large":"http://graph.facebook.com/100004637132223/picture?type=large","full_permalink":"http://stage.diveboard.com/","total_nb_dives":1,"public_nb_dives":1,"public_dive_ids":[31671],"nickname":"New Nick","dan_data":null,"storage_used":{"dive_pictures":0,"monthly_dive_pictures":0,"orphan_pictures":0,"all_pictures":0},"quota_type":"per_month","quota_limit":524288000,"all_dive_ids":[31671],"pict":false,"advertisements":[],"ad_album_id":30711,"user_gears":[{"class":"UserGear","flavour":"private","category":"Computer","id":2106,"manufacturer":"Suunto","model":"Vyper","featured":null,"acquisition":null,"last_revision":null,"reference":null,"auto_feature":"never"}]},"user_authentified":true}
+ + + + + + + + + + + + +
Example to remove all user_gears from a dive
curl -s "http://stage.diveboard.com/api/V2/user" +-F 'auth_token=wtV6sxKrMdXXBV+dVrqhJs936KKrq0TQBw2toWjM+Lk=' +-F 'flavour=private' +-F "apikey=hwkzq4rhw9lq" +-F 'arg={"id":"12850", "user_gears": []}'
{"success":true,"error":[],"result":{"class":"User","flavour":"private","id":12850,"shaken_id":"U3T7iSQ","vanity_url":null,"qualifications":{},"picture":"http://graph.facebook.com/100004637132223/picture?type=normal","picture_small":"http://graph.facebook.com/100004637132223/picture?type=square","picture_large":"http://graph.facebook.com/100004637132223/picture?type=large","full_permalink":"http://stage.diveboard.com/","total_nb_dives":1,"public_nb_dives":1,"public_dive_ids":[31671],"nickname":"New Nick","dan_data":null,"storage_used":{"dive_pictures":0,"monthly_dive_pictures":0,"orphan_pictures":0,"all_pictures":0},"quota_type":"per_month","quota_limit":524288000,"all_dive_ids":[31671],"pict":false,"advertisements":[],"ad_album_id":30711,"user_gears":[]},"user_authentified":true}
+ + +## Deleting an object + +To delete an object, the HTTP method to use is DELETE + + + + + + + + + + + +
Example to delete a dive
curl -X DELETE -s "http://stage.diveboard.com/api/V2/dive/31671" +-F 'auth_token=wtV6sxKrMdXXBV+dVrqhJs936KKrq0TQBw2toWjM+Lk=' +-F "apikey=hwkzq4rhw9lq"
{"success":true,"result":null,"error":[],"user_authentified":true}
+ + +## Creating several objects of the same type at the same time + +In order to make batch creation easier, the ‘arg’ parameter may accept an array of Hash that all describe the same type of objects. + + + + + + + + + + + +
Example to create 2 different dives at the same time
curl -s "http://stage.diveboard.com/api/V2/dive" +-F 'auth_token=wtV6sxKrMdXXBV+dVrqhJs936KKrq0TQBw2toWjM+Lk=' +-F "apikey=hwkzq4rhw9lq" +-F 'arg=[{"user_id": "U3T7iSQ", "duration": 90, "maxdepth":40, "time_in": "2011-10-16T09:40:00Z", "spot":{"id":1843}},{"user_id": "U3T7iSQ", "duration": 50, "maxdepth":50, "time_in": "2011-10-17T09:40:00Z", "spot":{"id":1843}}]'
{"success":true,"error":[],"result":[{"class":"Dive","flavour":"public","id":31672,"shaken_id":"D3iddpx","time_in":"2011-10-16T09:40:00Z","duration":90,"maxdepth":40.0,"user_id":12850,"spot_id":1843,"temp_surface":null,"temp_bottom":null,"privacy":0,"weights":null,"safetystops":null,"divetype":[],"favorite":null,"buddy":[],"visibility":null,"trip_name":null,"water":null,"altitude":0,"fullpermalink":"http://stage.diveboard.com//D3iddpx","permalink":"//D3iddpx","complete":true,"thumbnail_image_url":"http://stage.diveboard.com/map_images/map_1843.jpg","thumbnail_profile_url":null,"guide":null,"shop_id":null,"notes":null,"public_notes":null,"diveshop":null,"current":null,"species":[],"gears":[],"user_gears":[],"dive_gears":[],"date":"2011-10-16","time":"09:40"},{"class":"Dive","flavour":"public","id":31673,"shaken_id":"D3mIIWQ","time_in":"2011-10-17T09:40:00Z","duration":50,"maxdepth":50.0,"user_id":12850,"spot_id":1843,"temp_surface":null,"temp_bottom":null,"privacy":0,"weights":null,"safetystops":null,"divetype":[],"favorite":null,"buddy":[],"visibility":null,"trip_name":null,"water":null,"altitude":0,"fullpermalink":"http://stage.diveboard.com//D3mIIWQ","permalink":"//D3mIIWQ","complete":true,"thumbnail_image_url":"http://stage.diveboard.com/map_images/map_1843.jpg","thumbnail_profile_url":null,"guide":null,"shop_id":null,"notes":null,"public_notes":null,"diveshop":null,"current":null,"species":[],"gears":[],"user_gears":[],"dive_gears":[],"date":"2011-10-17","time":"09:40"}],"user_authentified":true}
+ + +## Updating several objects of the same type at the same time + +An array within ‘arg’ can also be used to update several objects of the same type. + + + + + + + + + + + +
Example to update 2 different dives at the same time
curl -s "http://stage.diveboard.com/api/V2/dive" +-F 'auth_token=wtV6sxKrMdXXBV+dVrqhJs936KKrq0TQBw2toWjM+Lk=' +-F "apikey=hwkzq4rhw9lq" +-F 'arg=[{"id":31672,"duration": 91},{"id":31673,"maxdepth":51}]'
{"success":true,"error":[],"result":[{"class":"Dive","flavour":"public","id":31672,"shaken_id":"D3iddpx","time_in":"2011-10-16T09:40:00Z","duration":91,"maxdepth":40.0,"user_id":12850,"spot_id":1843,"temp_surface":null,"temp_bottom":null,"privacy":0,"weights":null,"safetystops":null,"divetype":[],"favorite":null,"buddy":[],"visibility":null,"trip_name":null,"water":null,"altitude":0,"fullpermalink":"http://stage.diveboard.com//D3iddpx","permalink":"//D3iddpx","complete":true,"thumbnail_image_url":"http://stage.diveboard.com/map_images/map_1843.jpg","thumbnail_profile_url":null,"guide":null,"shop_id":null,"notes":null,"public_notes":null,"diveshop":null,"current":null,"species":[],"gears":[],"user_gears":[],"dive_gears":[],"date":"2011-10-16","time":"09:40"},{"class":"Dive","flavour":"public","id":31673,"shaken_id":"D3mIIWQ","time_in":"2011-10-17T09:40:00Z","duration":50,"maxdepth":51.0,"user_id":12850,"spot_id":1843,"temp_surface":null,"temp_bottom":null,"privacy":0,"weights":null,"safetystops":null,"divetype":[],"favorite":null,"buddy":[],"visibility":null,"trip_name":null,"water":null,"altitude":0,"fullpermalink":"http://stage.diveboard.com//D3mIIWQ","permalink":"//D3mIIWQ","complete":true,"thumbnail_image_url":"http://stage.diveboard.com/map_images/map_1843.jpg","thumbnail_profile_url":null,"guide":null,"shop_id":null,"notes":null,"public_notes":null,"diveshop":null,"current":null,"species":[],"gears":[],"user_gears":[],"dive_gears":[],"date":"2011-10-17","time":"09:40"}],"user_authentified":true}
+ + +## Updating recursively several objects at the same time + +Now comes the tricky part. When you update an object (e.g. a dive) you can at the same time create or update another object that is referred by this dive. For that, just add the attributes you would like to change along with the ‘id’ attribute that was already provided. + + + + + + + + + + + +
Example to update recursively a dive and a user_gear in the same call
curl -s "http://stage.diveboard.com/api/V2/dive" +-F 'auth_token=wtV6sxKrMdXXBV+dVrqhJs936KKrq0TQBw2toWjM+Lk=' +-F "apikey=hwkzq4rhw9lq" +-F 'flavour=private' +-F 'arg={"id":31672, "duration":55, "user_gears":[{"id":2106, "model":"Vyper Air"}]}'
{"success":true,"error":[],"result":{"class":"Dive","flavour":"private","id":31672,"shaken_id":"D3iddpx","time_in":"2011-10-16T09:40:00Z","duration":55,"maxdepth":40.0,"user_id":12850,"spot_id":1843,"temp_surface":null,"temp_bottom":null,"privacy":0,"weights":null,"safetystops":null,"divetype":[],"favorite":null,"buddy":[],"visibility":null,"trip_name":null,"water":null,"altitude":0,"fullpermalink":"http://stage.diveboard.com//D3iddpx","permalink":"//D3iddpx","complete":true,"thumbnail_image_url":"http://stage.diveboard.com/map_images/map_1843.jpg","thumbnail_profile_url":null,"guide":null,"shop_id":null,"notes":null,"public_notes":null,"diveshop":null,"current":null,"species":[],"gears":[{"class":"UserGear","flavour":"private","category":"Computer","id":2106,"manufacturer":"Suunto","model":"Vyper Air","featured":false,"acquisition":null,"last_revision":null,"reference":null,"auto_feature":"never"}],"user_gears":[{"class":"UserGear","flavour":"private","category":"Computer","id":2106,"manufacturer":"Suunto","model":"Vyper Air","featured":false,"acquisition":null,"last_revision":null,"reference":null,"auto_feature":"never"}],"dive_gears":[],"date":"2011-10-16","time":"09:40","dan_data":null,"dan_data_sent":null,"storage_used":0,"profile_ref":null},"user_authentified":true}
+ + +## Creating recursively objects + +This type of call can be very useful to prevent chaining multiple calls. In the example below, instead of calling first the API to create a user_gear and making a second call to assign that user_gear to the dive, only one call can do the trick. + + + + + + + + + + + +
Example to create a new user_gear and assigning an existing user_gear to a dive
curl -s "http://stage.diveboard.com/api/V2/dive" +-F 'auth_token=wtV6sxKrMdXXBV+dVrqhJs936KKrq0TQBw2toWjM+Lk=' +-F "apikey=hwkzq4rhw9lq" +-F 'flavour=private' +-F 'arg={"id":31672, "user_gears":[{"id":2106}, {"user_id":12850,"category":"Computer","manufacturer":"Mares","model":"Icon HD"}]}'
{"success":true,"error":[],"result":{"class":"Dive","flavour":"private","id":31672,"shaken_id":"D3iddpx","time_in":"2011-10-16T09:40:00Z","duration":91,"maxdepth":40.0,"user_id":12850,"spot_id":1843,"temp_surface":null,"temp_bottom":null,"privacy":0,"weights":null,"safetystops":null,"divetype":[],"favorite":null,"buddy":[],"visibility":null,"trip_name":null,"water":null,"altitude":0,"fullpermalink":"http://stage.diveboard.com//D3iddpx","permalink":"//D3iddpx","complete":true,"thumbnail_image_url":"http://stage.diveboard.com/map_images/map_1843.jpg","thumbnail_profile_url":null,"guide":null,"shop_id":null,"notes":null,"public_notes":null,"diveshop":null,"current":null,"species":[],"gears":[{"class":"UserGear","flavour":"private","category":"Computer","id":2106,"manufacturer":"Suunto","model":"Vyper","featured":false,"acquisition":null,"last_revision":null,"reference":null,"auto_feature":"never"},{"class":"UserGear","flavour":"private","category":"Computer","id":2107,"manufacturer":"Mares","model":"Icon HD","featured":false,"acquisition":null,"last_revision":null,"reference":null,"auto_feature":"never"}],"user_gears":[{"class":"UserGear","flavour":"private","category":"Computer","id":2106,"manufacturer":"Suunto","model":"Vyper","featured":false,"acquisition":null,"last_revision":null,"reference":null,"auto_feature":"never"},{"class":"UserGear","flavour":"private","category":"Computer","id":2107,"manufacturer":"Mares","model":"Icon HD","featured":false,"acquisition":null,"last_revision":null,"reference":null,"auto_feature":"never"}],"dive_gears":[],"date":"2011-10-16","time":"09:40","dan_data":null,"dan_data_sent":null,"storage_used":0,"profile_ref":null},"user_authentified":true}
+ + +## Uploading a ZXL or UDCF file + +This call will let you upload a profile file in a Diveboard supported format (currently DAN DL7 (aka ZXL or ZXU) and UDCF). + +The file will be analyzed and stored and as an output you get a list of the dive profiles present in the file in a digested format as well as their id within the file and the file id itself. This can be used to be bound to a dive. + + + + + + + + + + + + + +
Example to upload a dive profile file (here zxu) and retrieving the file id and the list of dive profiles in the file
$ curl -F "filename=@carlo.zxu" \ + -F "token=tnNxf1D169xCB32RGgQx3b3EcQavksyP5A3ssgLtAj4=" \ + -F "apikey=7hvvgobT6cnios" \ + http://www.diveboard.com/api/upload_profile
{"success":"true","nbdives":"13","dive_summary":[{"number":0,"date":"2004-09-07","time":"18:54","duration":8,"max_depth":60.1,"mintemp":25.0,"maxtemp":0.0,"newdive":true},{"number":1,"date":"2004-09-10","time":"17:29","duration":9,"max_depth":10.0,"mintemp":25.0,"maxtemp":0.0,"newdive":true},{"number":2,"date":"2004-09-10","time":"17:40","duration":11,"max_depth":20.1,"mintemp":26.0,"maxtemp":0.0,"newdive":true},{"number":3,"date":"2004-09-10","time":"17:52","duration":11,"max_depth":30.1,"mintemp":26.0,"maxtemp":0.0,"newdive":true},{"number":4,"date":"2004-09-10","time":"18:05","duration":13,"max_depth":40.1,"mintemp":26.0,"maxtemp":0.0,"newdive":true},{"number":5,"date":"2004-09-10","time":"18:19","duration":13,"max_depth":50.0,"mintemp":26.0,"maxtemp":0.0,"newdive":true},{"number":6,"date":"2004-09-10","time":"18:33","duration":23,"max_depth":60.0,"mintemp":26.0,"maxtemp":0.0,"newdive":true},{"number":7,"date":"2004-12-02","time":"17:05","duration":25,"max_depth":50.0,"mintemp":20.0,"maxtemp":0.0,"newdive":true},{"number":8,"date":"2005-09-25","time":"11:02","duration":52,"max_depth":33.2,"mintemp":17.0,"maxtemp":0.0,"newdive":true},{"number":9,"date":"2006-01-15","time":"13:36","duration":51,"max_depth":38.0,"mintemp":12.0,"maxtemp":0.0,"newdive":true},{"number":10,"date":"2006-07-16","time":"12:10","duration":51,"max_depth":33.0,"mintemp":18.0,"maxtemp":0.0,"newdive":true},{"number":11,"date":"2006-07-16","time":"14:41","duration":63,"max_depth":29.1,"mintemp":19.0,"maxtemp":0.0,"newdive":true},{"number":12,"date":"2006-10-15","time":"12:33","duration":73,"max_depth":26.1,"mintemp":20.0,"maxtemp":0.0,"newdive":true}],"fileid":1333}
+ + +## Error catching + +$ curl http://www.diveboard.com/api/V2/user + +{"success":false,"error":[{"error":"What do you want me to do ? you should specify 'arg'","object":null}]} + +$ curl "http://www.diveboard.com/api/V2/user?arg=%7Bid:48,nickname:'coucou'%7D&auth_token=ip4rHSSD9/diOWR3szonh7ikbhl0k9g/UgMSTBfjb00=&apikey=xxXXX6XXX6XxxxX6XXXX" + +{"success":true,"error":[{"error":"Forbidden","object":{"id":48,"nickname":"coucou"}}],"result":{"class":"User","flavour":"public","id":48,"vanity_url":"pascal","qualifications":{"featured":[{"org":"CMAS","title":"2 stars diver","date":"2011-07-26"},{"org":"PADI","title":"Advanced Open Water","date":"2011-07-25"},{"org":"CMAS","title":"Nitrox","date":"2011-10-17"}],"other":[{"org":"Other","title":"Cayman Island Lionfish Culling License","date":"2011-11-08"},{"org":"CMAS","title":"1 star","date":"2007-06-01"}]},"picture":"http://www.diveboard.com/user_images/48.png","picture_small":"http://www.diveboard.com/user_images/48.png","picture_large":"http://www.diveboard.com/user_images/48.png","full_permalink":"http://www.diveboard.com/pascal","total_nb_dives":66,"public_nb_dives":29,"public_dive_ids":["728","33","34","30","29","28","27","26","25","24","23","22","10305","555","1850","1851","2434","2435","2436","2437","2438","2439","2442","2443","2532","2533","2569","2570","5632"],"nickname":"Pascal"}} + +$ curl "http://www.diveboard.com/api/V2/dive?arg=%7Bid:2434, duration:123%7D&auth_token=ip4rHSSD9/diOWR3szonh7ikbhl0k9g/UgMSTBfjb00=&apikey=xxXXX6XXX6XxxxX6XXXX" + +{"success":true,"error":[{"error":"Forbidden","object":{"id":2434,"**duration**":**123**}}],"result":{"class":"Dive","flavour":"public","id":2434,"time_in":"2011-10-16T09:40:00Z","duration":53,"maxdepth":"20.1","user_id":48,"spot_id":1843,"temp_surface":20.0,"temp_bottom":19.0,"privacy":0,"weights":null,"safetystops":"[]","divetype":["recreational","Autonomy"],"favorite":null,"buddy":[],"visibility":null,"trip_name":"Nitrox training - Marseilles","water":null,"altitude":0,"fullpermalink":"http://www.diveboard.com/pascal/2434","complete":true,"thumbnail_image_url":"http://www.diveboard.com/map_images/map_1843.jpg","thumbnail_profile_url":"http://www.diveboard.com/pascal/2434/profile.png?g=small_or&u=m","species":[],"guide":"","shop_id":812,"notes":null,"public_notes":null,"diveshop":{"name":"ATOLL - DEEP SUB","url":"http://www.atollplongee.com","guide":"","id":812},"gears":[],"user_gears":[],"dive_gears":[],"date":"2011-10-16","time":"09:40"}} + +# Objects + +### USER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterR +E +A +DW +R +I +T +ECan be nilType/FormatPresent in flavoursComments for readComments for write
idXXINTEGERallthe id of the dive to update +if absent, a new dive will be created
shaken_idXSTRINGallthis attribute is a obfuscated version of the id. It will always be the same for a given object.
vanity_urlXXSTRINGall
qualificationsXQUALIFICATION Objectall
pictureXURLall
picture_smallXURLall
picture_largeXURLall
full_permalinkXURLallFull direct link to the user’s logbook on Diveboard
permalinkXURLallRelative path to the logbook (e.g. "/toto")
total_nb_divesXINTEGERallNumber of dives including external dives
public_nb_divesXINTEGERallNumber of public dives
public_dive_idsXARRAY of INTEGERallList of all the public dive IDs
locationXSTRINGall2 letters country code of the user in lowercase
nicknameXXSTRINGallMain name displayed all over Diveboard
auto_publicXBOOLEANallPrivate data, indicates whether the user wants to set the dive as public by default
dan_dataXXHASHprivatePrivate data used to send DAN forms +DO NOT USE
storage_usedXHASHprivateDetail of the storage used on Diveboard (for pictures mainly) +DO NOT USE
quota_typeXSTRINGprivateStorage limit type +DO NOT USE
quota_limitXINTEGERprivateStorage limit +DO NOT USE
all_dive_idsXARRAY of INTEGERprivateList of all dives for this user, including private dives
pictXBOOLEANprivateDoes the user have a custom picture +DO NOT USE
advertisementsXARRAYprivateDO NOT USE
ad_album_idXINTEGERprivateDO NOT USE
user_gearsXXARRAY of USER_GEAR objectsprivateThe gear owned by the user that will be used on various dives
aboutXDO NOT USE
emailXDO NOT USE
contact_emailXDO NOT USE
locationXallCountry indicator
settingsXDO NOT USE
total_ext_divesXXINTEGERprivateNumber of dives not on Diveboard, so that total_nb_dives reflects the real number of dives of the user
divesX
wallet_picturesXARRAY of PICTURE objectsprivategives an array of Picture objects in user wallet
wallet_pictures_idXARRAY OF INTEGERprivateSets the array of ids of pictures in user wallet
+ + +### QUALIFICATION OBJECT + + + + + + + + + + + + + + + + + + + + +
ParameterCan be nilType/FormatComments
featuredNOARRAY OF QUALIF_DETAILList of qualifications that will appear on the profile
otherNOARRAY OF QUALIF_DETAILList of qualifications that will only appear on the user’s logbook cover
+ + +### QUALIF_DETAIL Object + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterCan be nilType/FormatComments
orgNOSTRINGCertification Organisation
titleNOSTRINGTitle of the certification
dateNOSTRING +YYYY-MM-DDDate of certification
+ + +### EXTERNAL USER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterR +E +A +DW +R +I +T +ECan be nilType/FormatPresent in flavoursComments for readComments for write
idXXINTEGERallthe id of the external user object to update +if absent, a new object will be created
nicknameXXXSTRINGallNickname of the person
pictureXXURLallstandard version of the user’s picture if availablefor setting this attribute for non-facebook users, use the attribute picturl
picture_smallXXURLallsmall version of the user’s picture if availablefor setting this attribute for non-facebook users, use the attribute picturl
picture_largeXXURLalllarge version of the user’s picture if availablefor setting this attribute for non-facebook users, use the attribute picturl
picturlXXURLpermanent URL to the picture of the user (external url possible, should not be used for facebook users)
fb_idXXXINTEGERprivateFacebook ID
emailXXXTEXTprivateUser’s email address
+ + +### DIVE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterR +E +A +DW +R +I +T +ECan be nilType/FormatPresent in flavoursComments for readComments for write
idXXINTEGERallthe id of the dive to update +if absent, a new dive will be created
shaken_idXSTRINGallthis attribute is a obfuscated version of the id. It will always be the same for a given object.
user_idXXINTEGERallid of the dive’s ownerid of the dive’s owner
spotXXSPOT objectmobileThe spot tied to this dive - either an existing spot or a new one +if no spot is used, MUST use the spot id 1 (sorry) {id = 1}
spot_idXINTEGERall
time_inXXDATETIMEall"YYYY-MM-DD HH:MM:SS" when diver entered the sea in local time"YYYY-MM-DD HH:MM:SS" when diver entered the sea in local time
maxdepthXXFLOATallin metersin meters
durationXXINTEGERallin minutesin minutes
temp_surfaceXXXFLOATallTemperature of the water at the surface in celsiusTemperature of the water at the surface in celsius
temp_bottomXXXFLOATallTemperature of the water at the bottom in celsiusTemperature of the water at the bottom in celsius
privacyXXXINTEGERall1 = dive is private, 0 = dive is public1 = dive is private, 0 = dive is public
weightsXXXFLOATallin kgin kg
safetystopsXXXJSON of ARRAY of SAFETYSTOPallthe list of safety stops +e.g: [["6","3"],["3","3"]]the list of safety stops
divetypeXXXARRAY of STRINGSallthe list of the dive types done - strings are free fields +e.g: ["training","deep dive","wreck"]the list of the dive types done - strings are free fields +e.g: ["training","deep dive","wreck"]
favoriteXXXBOOLEANallfalse or null = dive is not in the favorite set +true= dive is in the favorite setfalse = dive is not in the favorite set +true= dive is in the favorite set
buddiesXXARRAY of USER and/or EXTERNAL_USER objectsall
buddiesXARRAY of BUDDY objectsall
visibilityXXXSTRINGallstring taken in : 'bad','average','good','excellent'string taken in : 'bad','average','good','excellent'
trip_nameXXXSTRINGallMaximum 255 characters, free fieldMaximum 255 characters, free field
waterXXXSTRINGallstring taken in : 'salt','fresh'string taken in : 'salt','fresh'
currentXXXSTRINGallstring taken in : 'none','light','medium','strong','extreme'string taken in : 'none','light','medium','strong','extreme'
altitudeXXXFLOATallin metersin meters
fullpermalinkXURLalldirect full url to the dive (including http://xxx.diveboard.com/....)
permalinkXSTRINGallDEPRECATED +path to the dive (without the leading http://xxx.diveboard.com)
completeXBOOLalltrue if the dive could be made public (i.e. has at least a spot, max depth & duration)
thumbnail_image_urlXSTRINGallurl to a square thumbnail image representing the dive (128x128)
thumbnail_profile_urlXXSTRINGallurl to a thumbnail representing the dive profile data graph
speciesXXXARRAY of SPECIESallarray of the species spotted during the dive - only "s-XXXXX" (c- gets replaced by its s-) species => [{:id => "s-1234"}, {:id => "s-2345"}] +array of the species spotted during the dive as scientific name "s-XXXX" or common name "c-XXXX" species => [{:id => "s-1234"}, {:id => "s-2345"}] +
guideXXXSTRINGallname of the guidename of the guide
shopXXXSHOP objectallthe dive shop the user dived with, when the shop already exists in Diveboard database
shop_idXXINTEGERallid of the dive shop used in that dive
diveshopXXHASHDEPRECATED +A Hash containing the following key, to enable a free fill in when a diveshop does not exists in Diveboard database : +- name : name of the shop +- url : url of the shop +- country : country code +- town : town name
diveshopXXHASHallDEPRECATED +A Hash containing some of the following key. It is constructed based on the ‘diveshop’ value, and overwritten with the values of ‘shop’ and ‘guide’ if available. + +At least one of the two following attributes are present : +- name : name of the shop +- guide : name of the guide + +The following attributes may be present : +- url : url of the shop +- country : country code +- town : town name
notesXXXSTRINGallnotes for the dive (free field) +readable only by ownernotes for the dive (free field)
public_notesXXSTRINGallnotes for the dive (free field)notes for the dive (free field)
tanksXXXARRAY of TANK objectprivateTanks used during the dive
gearsXallGear used for the dive (Both user_gears and dive_gears)
user_gearsXXXARRAY of USER_GEAR objectall
dive_gearsARRAY of DIVE_GEAR objectall
dateXXDATEallDate of the diveYYYY-MM-DD
timeXXTIMEallTime of the diveHH:MM 24-hr, "local" timezone to the spot
dan_dataXXXDAN ObjectprivateDO NOT USE
dan_data_sentXXprivateDO NOT USE
storage_usedprivateDO NOT USE
profile_refXXXSTRINGprivateProfile reference for UDCF uploads
picturesXXmobile
numberXXXINTEGERallNumber of the dive in the logbook
send_to_danXDO NOT USE
raw_profileXXXARRAY of PROFILE_SAMPLE objectspublic_with_profileDive profile data
featured_pictureXXmobile
featured_gearsXmobile
other_gearsmobile
+ + +### SAFETYSTOP + +Each safety stop is stored as an array of the depth and the duration. + + + + + + + + + + + + + + + + + + + + +
Position in ArrayType / FormatMandatory/OptionalDescription
0INTEGERMANDATORYdepth in meters
1INTEGERMANDATORYtime in minutes
+ + +example : [5,3] => 5 meters, 3 minutes stop + +### PROFILE_SAMPLE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterCan be nilType/FormatComments
secondsNOINTEGERtime of the sample since the beginning of the dive
depthYESFLOATUnit: meters
current_water_temperatureYESFLOATUnit: celsius degrees
main_cylinder_pressureYESFLOATUnit: bar
heart_beatsYESFLOATUnit: beat per minutes
deco_violationNOBOOLEANdefaults to false when absent, indicates when the diver has not respected his decompression procedure
deco_startNOBOOLEANdefaults to false when absent,indicates when the dive started to have decompression stop (on top of the 3min for safety)
ascent_violationNOBOOLEANdefaults to false when absent,indicates when the diver went up too fast
bookmarkNOBOOLEANdefaults to false when absent,indicates then the diver has logged a bookmark during the dive
surface_eventNOBOOLEANdefaults to false when absent,indicates when the diver has reached the surface
+ + +### BUDDY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterCan be nilType/FormatComments
nameSTRINGName of your buddy - free text
db_idXINTEGERid of the buddy on diveboard
fb_idXINTEGERfacebook id of the buddy
emailXSTRINGemail of your buddy
picturlXSTRINGurl to a picture of your buddy
+ + +### DIVE_GEAR + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterRWCan be nilType/FormatPresent in flavoursComments for readComments for write
idXXXINTEGERallthe dive_gear object idthe dive_gear object id
categoryXXXSTRINGallin 'BCD','Boots','Computer','Compass','Camera','Cylinder','Dive skin','Dry suit','Fins','Gloves','Hood','Knife','Light','Lift bag','Mask','Other','Rebreather','Regulator','Scooter','Wet suit'in 'BCD','Boots','Computer','Compass','Camera','Cylinder','Dive skin','Dry suit','Fins','Gloves','Hood','Knife','Light','Lift bag','Mask','Other','Rebreather','Regulator','Scooter','Wet suit'
manufacturerXXXSTRINGallManufacturer’s nameManufacturer’s name
modelXXXSTRINGallModel’s nameModel’s name
featuredXXXBOOLalltrue if the gear is featured in the divetrue if the gear is featured in the dive
+ + +### USER_GEAR + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterRWCan be nilType/FormatPresent in flavoursComments for readComments for write
idXXXINTEGERallthe dive_gear object idthe dive_gear object id
categoryXXXSTRINGallin 'BCD','Boots','Computer','Compass','Camera','Cylinder','Dive skin','Dry suit','Fins','Gloves','Hood','Knife','Light','Lift bag','Mask','Other','Rebreather','Regulator','Scooter','Wet suit'in 'BCD','Boots','Computer','Compass','Camera','Cylinder','Dive skin','Dry suit','Fins','Gloves','Hood','Knife','Light','Lift bag','Mask','Other','Rebreather','Regulator','Scooter','Wet suit'
manufacturerXXXSTRINGallManufacturer’s nameManufacturer’s name
modelXXXSTRINGallModel’s nameModel’s name
featuredXXXBOOLalltrue if the gear is featured in the divetrue if the gear is featured in the dive
acquisitionXXXDATEprivateYYYY-MM-DD of acquisitionYYYY-MM-DD of acquisition
auto_featureXXXSTRINGprivatedefines in which section the gear will go : select in 'never','featured','other'defines in which section the gear will go : select in 'never','featured','other'
last_revisionXXXDATEprivateYYYY-MM-DD of last revisionYYYY-MM-DD of last revision
referenceXXXSTRINGprivatefree field with reference numberfree field with reference number
+ + +### SPECIES + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterCan be nilType/FormatComments
idSTRINGId of the species either "s-12435413" (scientific name) or "c-214324" (common name)
nameXSTRINGPreferred common name of the species
snameSTRINGScientific name of the species
linkXSTRINGLink to species information page ( EOL.org )
thumbnail_hrefXSTRINGurl to a thumbnail of the fish picture
pictureXSTRINGurl to a picture of the species
+ + +### SHOP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterRWCan be nilType/FormatPresent in flavoursComments for readComments for write
idXXXINTEGERallthe id of the dive shop to update +if absent, a new dive will be createdthe id of the dive shop to update +if absent, a new dive will be created
nameXXXSTRINGallthe name of the dive shopthe name of the dive shop
latXXXFLOATallLatitude of the dive shopLatitude of the dive shop
lngXXXFLOATallLongitude of the dive shopLongitude of the dive shop
addressXXXSTRINGallthe dive shop addressthe dive shop address
emailXXXSTRINGallcontact email for the dive shopcontact email for the dive shop
webXXXSTRINGallurl of the dive shop (including the leading http://)url of the dive shop (including the leading http://)
phoneXXXSTRINGalldive shop’s phonedive shop’s phone
logo_urlXXXINTEGERallurl to the logo of the dive shop (including the leading http://)url to the logo of the dive shop (including the leading http://)
dive_idsXARRAY of (DIVE object).idsearch_lightArray of ids of dives done in that spotArray of ids of dives done in that spot
dive_countXINTEGERsearch_lightNumber of dives Number of dives done in this spot
+ + +### Spot + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterRWCan be nilType/FormatPresent in flavoursComments for readComments for write
idXXXINTEGERallthe id of the spot to update +if absent, a new dive will be createdthe id of the spot to update +if absent, a new dive will be created
shaken_idXSTRINGall
nameXXSTRINGallthe name of the spotthe name of the spot
latXXFLOATallLatitude of the dive shopLatitude of the dive shop
lngXXFLOATallLongitude of the dive shopLongitude of the dive shop
zoomXXINTEGERallpreferred zoom level for a nice render in a map (7-> 12)preferred zoom level for a nice render in a map (7-> 12)
locationXOBJECTallWhere the spot is located
location_idXINTEGERallWhere the spot is located
regionXXOBJECTallBody of water where the spot is located
region_idXXINTEGERBody of water where the spot is located
country_idXXINTEGERallCountry where the spot is locatedCountry where the spot is located
private_user_idXXXINTEGERalluser id of the owner of the spot - is set spot is "private" i.e. not moderateduser id of the owner of the spot - is set spot is "private" i.e. not moderated
country_codeXXSTRINGallISO Country code (2 letters) +E.g. FR for France, GB for United Kingdom, MT for Malta
country_nameXSTRINGallFull country name
country_flag_bigXURLallURL to the big flag image
country_flag_smallXURLallURL to the small flag image
+ + +### LOCATION + +A location is the area where a spot is located, mainly a big city, or a zone i.e. Sidney, NSW or San-Franciso... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterRWCan be nilType/FormatPresent in flavoursComments for readComments for write
idXXINTEGERallthe id of the location to update +if absent, a new dive will be createdlocation can NOT be updated
nameXXSTRINGallthe name of the locationthe name of the location
country_idXXINTEGERallcountry_id where location iscountry_id where location is
+ + +**REGION** + +A location is the body of water where a spot is located, Atlantic Ocean, Mediterranean Sea, Pacific Ocean... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterRWCan be nilType/FormatPresent in flavoursComments for readComments for write
idXXINTEGERallthe id of the location to update +if absent, a new dive will be createdlocation can NOT be updated
nameXXSTRINGallthe name of the locationthe name of the location
+ + +### TANKS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterRWCan be nilType/FormatPresent in flavoursComments for readComments for write
idXXXINTEGERallTank idTank id
materialXXXSTRINGallstring in 'aluminium','steel'string in 'aluminium','steel'
gasXXXSTRINGallstring in 'air','EANx32','EANx36','EANx40','custom'string in 'air','EANx32','EANx36','EANx40','custom'
volumeXXXFLOATallVolume of the tank in LVolume of the tank in L
multitankXXXINTEGERallnumber of such tanks (1 or 2 for dual tanks)number of such tanks (1 or 2 for dual tanks)
o2XXXINTEGERallpercentage of o2 in gaz 0-100 +only used if gas=’custom’percentage of o2 in gaz 0-100 +only used if gas=’custom’
n2XXXINTEGERallpercentage of n2 in gaz 0-100 +only used if gas=’custom’percentage of n2 in gaz 0-100 +only used if gas=’custom’
heXXXINTEGERallpercentage of he in gaz 0-100 +only used if gas=’custom’percentage of he in gaz 0-100 +only used if gas=’custom’
time_startXXXINTEGERalltime in minutes from the start of the dive when diver switched to this tanktime in minutes from the start of the dive when diver switched to this tank
p_startXXXFLOATallInitial pressure in bottle in barInitial pressure in bottle in bar
p_endXXXFLOATallFinal pressure in bottle in barFinal pressure in bottle in bar
+ + +### UNITS + +The attribute "Units" is deprecated. To get or set the preferred units of a user, use the preferred_units attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
distanceSTRING +"m" or “ft”MN
weightSTRING +“kg” or “lbs”MY
temperatureSTRING +“C” or “F”MY
pressure“bar” or “psi”MY
+ + +### Object ERROR + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameType / FormatMandatory/OptionalNull?Description
errorSTRINGMNtechnical error message
objectOBJECTMYthe part of the input parameter that is responsible for the error (for debugging purposes)
error_codeMNerror code (will be implemented in future version)
diff --git a/public/img/creative_commons.png b/public/img/creative_commons.png new file mode 100644 index 0000000000000000000000000000000000000000..49f272f828c17c9f52b64c27fa6a3c399bee9344 GIT binary patch literal 5281 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 literal 0 HcmV?d00001