Hello everyone, in this article i will do a global tutorial which is supposed to teach you the basics to manipulate your own avatars.
Everything will be done through the API.
To follow this tutorial I expect you to
If you're fine with all of that, let us begin, you should have a JWT available at this moment in order to move forward. We will as example the manipulation of the following avatar :
@prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> .
@prefix : <http://orange-labs.fr/thingin/tutorial#> .
:Sensor01
a dogont:SingleTemperatureSensor .
I'm taking on purpose the simplest avatar possible, the goal here is just to perform some very simple manipulation, we will enrich it later with an update.
You can notice a cool trick here : the empty prefix is valid in turtle, you may as well use it to compress as much as possible the size of your payload. Do not use ''_'' it is reserved by Turtle.
*/!\ MAKE SURE THE FULL IRI DEFINED FOR YOUR SENSOR POINTS TOWARD A DOMAIN WHERE YOU ARE ALLOWED TO CREATE AVATAR /!*
First of all, we want to create our avatar into Thing'in, so let's take a look at the API, we will mainly focus on the /avatars resources for the moment:
* : We will talk about the update later, don't worry.
Everything listed here is made to be used on single avatar. That's great ! We have a single avatar we want to create, you can use the Swagger API or you can do it with CURL Request (make sure your proxy is active, if you see what i mean...). I will show CURL request for this tutorial :
''/!\ BEWARE, DO NOT SIMPLY COPY PASTE THE CURL REQUESTS AS YOU WILL USE THE SAME TOKEN AS ME WHICH WILL HAVE EXPIRED BY THE TIME YOU USE THIS MANUAL, REPLACE IT WITH YOUR OWN TOKEN /!''
Create avatar curl request :
curl -X POST --header 'Content-Type: text/turtle' --header 'Accept: application/json' --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb21haW5zIjpbIiJdLCJqdGkiOiI3NzBiMDVkOC05ZmRlLTExZTgtODliOC1mYTE2M2VkMDk3N2UiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTUzNDM1MDI0NiwiaWF0IjoxNTM0MjYzODQ2LCJpc3MiOiJUaGluZ19pbiIsImV4dGVybmFsaWQiOiJhZG1pbiIsInNjb3BlcyI6WyJhZG1pbiJdLCJraWQiOiJlZjU3MjVkNi03NGU5LTQzMjktODI3Zi04YjJkZGQzYzE2NjAifQ.iS20PSI_JC1NW-KgrH9UwSAEBozN-lfocvdDwW0YHOM' -d '%40prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> . \
%40prefix : <http://orange-labs.fr/thingin/tutorial#> . \
\
:Sensor01 \
a dogont:SingleTemperatureSensor .' 'http://api-dev-thingin.nprpaas.ddns.integ.dns-orange.fr/avatars/'
As you can see, I used the JWT in the authorization header preceeded by "Bearer " to perform an authentified action into the API. I sent data in the form of turtle so that's why the Content-Type header is set to text/turtle and the payload holds the turtle data.
You should receive an empty body, with a 201 response code and the response headers should look like so :
{
"access-control-allow-origin": "*",
"cache-control": "proxy-revalidate",
"connection": "Keep-Alive",
"content-length": "5",
"content-type": "application/json",
"date": "Tue, 14 Aug 2018 16:25:14 GMT",
"location": "http://10.226.225.229/avatars/d8d18e46-b04b-4b36-adbe-5b14172833e5",
"server": "nginx/1.6.2"
}
The important part of the response header is the field location, the last part is the UUID
we gave to our avatar. Perfect, we made our first avatar into Thing'in ! Let us check, verify, proove to ourselves, that the avatar is indeed saved in the system and accessible.
Read avatar curl request :
curl -X GET --header 'Accept: application/json' --header 'Read-Mode: strict' --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb21haW5zIjpbIiJdLCJqdGkiOiI3NzBiMDVkOC05ZmRlLTExZTgtODliOC1mYTE2M2VkMDk3N2UiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTUzNDM1MDI0NiwiaWF0IjoxNTM0MjYzODQ2LCJpc3MiOiJUaGluZ19pbiIsImV4dGVybmFsaWQiOiJhZG1pbiIsInNjb3BlcyI6WyJhZG1pbiJdLCJraWQiOiJlZjU3MjVkNi03NGU5LTQzMjktODI3Zi04YjJkZGQzYzE2NjAifQ.iS20PSI_JC1NW-KgrH9UwSAEBozN-lfocvdDwW0YHOM' 'http://api-dev-thingin.nprpaas.ddns.integ.dns-orange.fr/avatars/d8d18e46-b04b-4b36-adbe-5b14172833e5'
For this request, i used the entry into the API which allows me to read an avatar. There are lots of parameters which may be used, we will only focus on setting the Authorization header, the Accept header, the UUID'' of the avatar and the Read-Mode header. The Read-Mode header is a very convenient parameter which will help you out later, it has two mode :
Just use the strict mode for this once, we don't have object properties anyway, also select application/json
for the Accept header. For the result read request, you should receive a body looking like this:
{
"_depth": 0,
"_domain": "http://orange-labs.fr/thingin/",
"_iri": "http://orange-labs.fr/thingin/tutorial#Sensor01",
"_last_updated": 1534263915214,
"_uuid": "d8d18e46-b04b-4b36-adbe-5b14172833e5",
"_owner": "admin",
"_static": false,
"_class": "http://elite.polito.it/ontologies/dogont.owl#SingleTemperatureSensor"
}
Here you have the result of a very simple read, it may seem a bit frightening but it's not all the much. Every field starting with "_" is a metadata field, here is their meaning :
false
Not that hard right ? (Well, i hope )
Also, the response code should be 200, response headers are not interesting to look at for this request.
Now, Assuming you have not run away yet (Please don't !), we will follow with the same read but this time with the header Accept set to text/turtle
Read avatar in turtle curl request
curl -X GET --header 'Accept: text/turtle' --header 'Read-Mode: strict' --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb21haW5zIjpbIiJdLCJqdGkiOiI3NzBiMDVkOC05ZmRlLTExZTgtODliOC1mYTE2M2VkMDk3N2UiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTUzNDM1MDI0NiwiaWF0IjoxNTM0MjYzODQ2LCJpc3MiOiJUaGluZ19pbiIsImV4dGVybmFsaWQiOiJhZG1pbiIsInNjb3BlcyI6WyJhZG1pbiJdLCJraWQiOiJlZjU3MjVkNi03NGU5LTQzMjktODI3Zi04YjJkZGQzYzE2NjAifQ.iS20PSI_JC1NW-KgrH9UwSAEBozN-lfocvdDwW0YHOM' 'http://api-dev-thingin.nprpaas.ddns.integ.dns-orange.fr/avatars/d8d18e46-b04b-4b36-adbe-5b14172833e5'
You should receive a body looking like this:
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://orange-labs.fr/thingin/tutorial#Sensor01>
a <http://elite.polito.it/ontologies/dogont.owl#SingleTemperatureSensor> ;
<http://orange-labs.fr/fog/ont/iot.owl#uuid> "d8d18e46-b04b-4b36-adbe-5b14172833e5"^^xsd:string ;
<http://orange-labs.fr/fog/ont/iot.owl#lastUpdated> "1534263915214"^^xsd:long ;
<http://orange-labs.fr/fog/ont/iot.owl#owner> "admin"^^xsd:string .
A few things to note. First, we do not retrieve the same prefix as earlier, this kind of information is not preserved through the creation of the avatar. Next, part of the metadata we listed ahead are also present in RDF, in order to respect the semantic of turtle, we created generic data properties in the ontology http://orange-labs.fr/fog/ont/iot.owl, appliable to any avatar, to hold the metadata for an avatar. We note that owner, domain and depth are missing, this will be patched in the future, we still have refactoring to perform.
Last important thing i wanted you to understand, you can request your data in JSON or TURTLE, and you can also create or update your data using both JSON or TURTLE. I strongly advise you to use TURTLE in the beginning, JSON is a bit permissive and is reserved for experienced user who wants to optimize the speed of their request. JSON is less expensive in general processing, but only if you do it right.
We created an avatar, we checked it was indeed existing into Thing'In and we could retrieve its data. The next step will be the update, a tiny one, but still, an update.
Let's start from the payload we used at the beginning and add a simple data property :
@prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> .
@prefix gr: <http://purl.org/goodrelations/v1#> .
@prefix : <http://orange-labs.fr/thingin/tutorial#> .
:Sensor01
a dogont:SingleTemperatureSensor ;
gr:serialNumber "0001"^^xsd:string .
Note the adjustment into the syntax, we replaced the " . " at the end of " dogont:SingleTemperatureSensor " with " ; ", it means we will repeat the first part of this triple, in our case '':Sensor01''. So the payload right ahead, is strictly equivalent with the payload right below :
@prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> .
@prefix gr: <http://purl.org/goodrelations/v1#> .
@prefix : <http://orange-labs.fr/thingin/tutorial#> .
:Sensor01 a dogont:SingleTemperatureSensor .
:Sensor01 gr:serialNumber "0001"^^xsd:string .
If you're not at ease with kind of mechanism, go check https://www.w3.org/TR/turtle/ part 2.2 Predicate Lists and 2.3 Object Lists, they show you how to exploit turtle to avoid data repetition.
Back to the update topic, we added the data property gr:serialNumber ( in non-prefixed form : http://purl.org/goodrelations/v1#serialNumber) with the value "0001" as string to our payload. We must now perform an update request into the API. There are 3 methods to perform an update :
note : By properties, we mean data properties and object properties, it applies to both
In our case, we only want to add a new data property to our current avatar, we will take the set mode.
Update avatar using the SET method :
curl -X PUT --header 'Content-Type: text/turtle' --header 'Accept: application/json' --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb21haW5zIjpbIiJdLCJqdGkiOiI3NzBiMDVkOC05ZmRlLTExZTgtODliOC1mYTE2M2VkMDk3N2UiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTUzNDM1MDI0NiwiaWF0IjoxNTM0MjYzODQ2LCJpc3MiOiJUaGluZ19pbiIsImV4dGVybmFsaWQiOiJhZG1pbiIsInNjb3BlcyI6WyJhZG1pbiJdLCJraWQiOiJlZjU3MjVkNi03NGU5LTQzMjktODI3Zi04YjJkZGQzYzE2NjAifQ.iS20PSI_JC1NW-KgrH9UwSAEBozN-lfocvdDwW0YHOM' -d '%40prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> . \
%40prefix gr: <http://purl.org/goodrelations/v1#> . \
%40prefix : <http://orange-labs.fr/thingin/tutorial#> . \
\
:Sensor01 a dogont:SingleTemperatureSensor . \
:Sensor01 gr:serialNumber "0001"^^xsd:string .' 'http://api-dev-thingin.nprpaas.ddns.integ.dns-orange.fr/avatars/update/set/d8d18e46-b04b-4b36-adbe-5b14172833e5'
We did exaclty the same thing as the READ request for setting the UUID and the Authorization header and we set the payload just like we did for the avatar CREATE. You should receive an empty body, with a 201 response code and in the response headers, you should be able to find again the location containing the UUID of the update avatar.
Try reading it again with a curl request, if you have to change anything from your previous READ request, aside from token expiration, you have done something wrong. It should answer swiftly and give you a response looking like this :
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://orange-labs.fr/thingin/tutorial#Sensor01>
a <http://elite.polito.it/ontologies/dogont.owl#SingleTemperatureSensor> ;
<http://orange-labs.fr/fog/ont/iot.owl#uuid> "d8d18e46-b04b-4b36-adbe-5b14172833e5"^^xsd:string ;
<http://orange-labs.fr/fog/ont/iot.owl#lastUpdated> "1534268102527"^^xsd:long ;
<http://orange-labs.fr/fog/ont/iot.owl#owner> "admin"^^xsd:string ;
<http://purl.org/goodrelations/v1#serialNumber> "0001"^^xsd:string .
For those who managed to make it work, congratulations ! The others, send us some help, we will see what we can do to help you.
We can still see the metadata properties, the timestamp stored in lastUpdated has changed and the data property http://purl.org/goodrelations/v1#serialNumber we wanted to add has made its apparition in the response body.
Before going anywhere deeper, adding object properties and some other avatars, let's do some very basic tests with the update to see how to distinguish the replace and set mode.
Go back to the payload we used for the avatar creation :
@prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> .
@prefix gr: <http://purl.org/goodrelations/v1#> .
@prefix : <http://orange-labs.fr/thingin/tutorial#> .
:Sensor01
a dogont:SingleTemperatureSensor .
And update the avatar with this payload in set mode. I insist set mode.
curl -X PUT --header 'Content-Type: text/turtle' --header 'Accept: application/json' --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb21haW5zIjpbIiJdLCJqdGkiOiI3NzBiMDVkOC05ZmRlLTExZTgtODliOC1mYTE2M2VkMDk3N2UiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTUzNDM1MDI0NiwiaWF0IjoxNTM0MjYzODQ2LCJpc3MiOiJUaGluZ19pbiIsImV4dGVybmFsaWQiOiJhZG1pbiIsInNjb3BlcyI6WyJhZG1pbiJdLCJraWQiOiJlZjU3MjVkNi03NGU5LTQzMjktODI3Zi04YjJkZGQzYzE2NjAifQ.iS20PSI_JC1NW-KgrH9UwSAEBozN-lfocvdDwW0YHOM' -d '%40prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> . \
%40prefix gr: <http://purl.org/goodrelations/v1#> . \
%40prefix : <http://orange-labs.fr/thingin/tutorial#> . \
\
:Sensor01 \
a dogont:SingleTemperatureSensor .' 'http://api-dev-thingin.nprpaas.ddns.integ.dns-orange.fr/avatars/update/set/d8d18e46-b04b-4b36-adbe-5b14172833e5'
Try the read again. The avatar will remain unchanged. It is normal. As explained before, the set mode can only do updates of an existing property or create new ones, it can not delete anything. Let's do the very same update but this time using the replace mode:
curl -X PUT --header 'Content-Type: text/turtle' --header 'Accept: application/json' --header 'Namespace: IOT-Explorer' --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb21haW5zIjpbIiJdLCJqdGkiOiI3NzBiMDVkOC05ZmRlLTExZTgtODliOC1mYTE2M2VkMDk3N2UiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTUzNDM1MDI0NiwiaWF0IjoxNTM0MjYzODQ2LCJpc3MiOiJUaGluZ19pbiIsImV4dGVybmFsaWQiOiJhZG1pbiIsInNjb3BlcyI6WyJhZG1pbiJdLCJraWQiOiJlZjU3MjVkNi03NGU5LTQzMjktODI3Zi04YjJkZGQzYzE2NjAifQ.iS20PSI_JC1NW-KgrH9UwSAEBozN-lfocvdDwW0YHOM' -d '%40prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> . \
%40prefix gr: <http://purl.org/goodrelations/v1#> . \
%40prefix : <http://orange-labs.fr/thingin/tutorial#> . \
\
:Sensor01 \
a dogont:SingleTemperatureSensor .' 'http://api-dev-thingin.nprpaas.ddns.integ.dns-orange.fr/avatars/update/replace/d8d18e46-b04b-4b36-adbe-5b14172833e5'
Again, try the read again. Surprise ! The response body should look like this :
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://orange-labs.fr/thingin/tutorial#Sensor01>
a <http://elite.polito.it/ontologies/dogont.owl#SingleTemperatureSensor> ;
<http://orange-labs.fr/fog/ont/iot.owl#uuid> "d8d18e46-b04b-4b36-adbe-5b14172833e5"^^xsd:string ;
<http://orange-labs.fr/fog/ont/iot.owl#lastUpdated> "1534268967883"^^xsd:long .
We lost the data property http://purl.org/goodrelations/v1#serialNumber. This is happening because we update in replace mode an avatar with a partial content of the already existing avatar. Because a property was not listed anymore in the new avatar, it simply got removed from the avatar.
So why is update set useful ? It allows you to do partial update of a given avatar, in our case it's not that big of a deal because our avatar is really tiny, but when you have an avatar which looks like this :
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#100345>
a <http://orange-labs.fr/fog/ont/odparis.owl#signalisation-tricolore> ;
<http://orange-labs.fr/fog/ont/iot.owl#uuid> "dd86863f-6795-4cc2-bcea-4267adfc9f5c"^^xsd:string ;
<http://orange-labs.fr/fog/ont/iot.owl#lastUpdated> "1531148967563"^^xsd:long ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#materiau_l> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#cod_lumina> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_secteu> "10_HOPITAL SAINT LOUIS_SLT"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_suppor> "BP31 Non Obturé (avec vis)"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#nature_voi> "CR"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_region> "STV6-SLT"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#unitevie_s> "ANS"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_ouvrag> "SLT"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_regi_1> "Arrondissement 10"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#voievent_v> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#pw_lampe> "22.0"^^xsd:double ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#posx_ouvra> "602420.8125"^^xsd:double ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#hauteur_su> "0.0"^^xsd:double ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#numvoie_ou> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_supp_1> "Support SLT standard"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#dureevie_l> "0.0"^^xsd:double ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_lumina> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_lumi_1> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_lampef> "Source Phare diodes existants"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_voiedo> "CARREFOURS"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#bister_ouv> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_fourni> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#cod_ouvrag> "S14342"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_domain> "Signalisation lumineuse tricolore"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#modele_lum> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#type_suppo> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_four_1> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#posy_ouvra> "130194.0703"^^xsd:double ;
<http://www.opengis.net/gml/pos> "{"type": "Point","coordinates": [2.36952562967, 48.8721894962]}"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#cod_lampe> "0402012"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#dureevie_s> "30.0"^^xsd:double ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#objectid> "100345"^^xsd:integer ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_voie> "1445 / ALIBERT / CLAUDE VELLEFAUX / PARMENTIER"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#unitevie_l> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#pwc_lampe> "21.0"^^xsd:double ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#pwe_lampe> "0.0"^^xsd:double ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#faceop_ouv> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#cod_suppor> "0103003"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#materiau_s> ""^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#observatio> "PHARES CROIX ET VERT DIODES"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_lampe> "SLT LED--200-Vert---22W"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#lib_regime> "REGIME VERT"^^xsd:string ;
<http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#foyer> "S14342-03"^^xsd:string .
And all you want is to update the data property http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#modele_lum, you can see the advantage of allowing partial update. It makes the payload smaller, it will be faster to send on your side and faster to process on our side, win-win.
Following that, what if you wanted to remove only the data property http://orange-labs.fr/fog/ont/odparis.owl/signalisation-tricolore#modele_lum instead ? You would use the update unset mode. Using the unset mode, we do not look the values of the properties because all we do is to remove the properties listed in your partial avatar, you just have to use placeholder to make the avatar valid (either in JSON or Turtle).
Update our avatar to give it again the data property http://purl.org/goodrelations/v1#serialNumber, you can use set or replace, it will work in both case. If you have trouble go read again the beginning of the udpate description.
Right now your avatar should have again the data property http://purl.org/goodrelations/v1#serialNumber, we will remove this property using the update unset. Use the following payload :
@prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> .
@prefix gr: <http://purl.org/goodrelations/v1#> .
@prefix : <http://orange-labs.fr/thingin/tutorial#> .
:Sensor01
a dogont:SingleTemperatureSensor ;
gr:serialNumber ""^^xsd:string .
Note that i used an empty value for the data property, this is just a place holder, still make sure it uses the right datatype.
Update avatar using the UNSET method :
curl -X PUT --header 'Content-Type: text/turtle' --header 'Accept: application/json' --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb21haW5zIjpbIiJdLCJqdGkiOiI0N2IyMDZkNC1hMTI3LTExZTgtODliOC1mYTE2M2VkMDk3N2UiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTUzNDQ5MTQ3MSwiaWF0IjoxNTM0NDA1MDcxLCJpc3MiOiJUaGluZ19pbiIsImV4dGVybmFsaWQiOiJhZG1pbiIsInNjb3BlcyI6WyJhZG1pbiJdLCJraWQiOiIwNzA3OWIyMS02OTllLTQ0NGYtOTA4Yi0xYTQzZjg4NzZhNDcifQ.ehMr5lECHJwLZ36aZEg93-3fZRq8cunJu3Z7F8ozWFs' -d '%40prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> . \
%40prefix gr: <http://purl.org/goodrelations/v1#> . \
%40prefix : <http://orange-labs.fr/thingin/tutorial#> . \
\
:Sensor01 \
a dogont:SingleTemperatureSensor ; \
gr:serialNumber ""^^xsd:string .' 'http://api-dev-thingin.nprpaas.ddns.integ.dns-orange.fr/avatars/update/unset/d8d18e46-b04b-4b36-adbe-5b14172833e5'
It's been a long time, hasn't it ? Try to read the data again . Now the data property http://purl.org/goodrelations/v1#serialNumber has been removed from the avatar, perfect.
We will now create our second avatar ! Use the following payload to create a living room :
@prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> .
@prefix gr: <http://purl.org/goodrelations/v1#> .
@prefix : <http://orange-labs.fr/thingin/tutorial#> .
:LivingRoom01
a dogont:LivingRoom ;
dogont:contains :Sensor01 .
As you can see, we have our very first object property, it will connect the living room to the sensor, litterally meaning "The living room contains the sensor". You shouldn't need my help to perform the avatar creation, its exactly the same thing as for the sensor creation, except the payload.
Also, we can afford to have an object property directly at the creation of the avatar because the avatar we are targeting through the ''contains'' property is ''already existing'', we allow to create edge only if both ends either already exists or will be created through the commit of the current operation. In our case, the target is already there and the source (the living room avatar node) will be created as long as the edge. In terms of process we always build the nodes first and then comes the edges.
Since i'm a nice guy, here's the curl request, just to make sure :
curl -X POST --header 'Content-Type: text/turtle' --header 'Accept: application/json' --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb21haW5zIjpbIiJdLCJqdGkiOiI0N2IyMDZkNC1hMTI3LTExZTgtODliOC1mYTE2M2VkMDk3N2UiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTUzNDQ5MTQ3MSwiaWF0IjoxNTM0NDA1MDcxLCJpc3MiOiJUaGluZ19pbiIsImV4dGVybmFsaWQiOiJhZG1pbiIsInNjb3BlcyI6WyJhZG1pbiJdLCJraWQiOiIwNzA3OWIyMS02OTllLTQ0NGYtOTA4Yi0xYTQzZjg4NzZhNDcifQ.ehMr5lECHJwLZ36aZEg93-3fZRq8cunJu3Z7F8ozWFs' -d '%40prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> . \
%40prefix gr: <http://purl.org/goodrelations/v1#> . \
%40prefix : <http://orange-labs.fr/thingin/tutorial#> . \
\
:LivingRoom01 \
a dogont:LivingRoom ; \
dogont:contains :Sensor01 .' 'http://api-dev-thingin.nprpaas.ddns.integ.dns-orange.fr/avatars/'
Remember what you did to retrieve the UUID of the sensor, i'm giving you an hint, it's in the response header, do the exact same thing for the living room and try doing a read on it. You should have something similar to this :
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://orange-labs.fr/thingin/tutorial#LivingRoom01>
a <http://elite.polito.it/ontologies/dogont.owl#LivingRoom> ;
<http://orange-labs.fr/fog/ont/iot.owl#uuid> "fde01614-3d34-432e-9e44-f52c491a2160"^^xsd:string ;
<http://orange-labs.fr/fog/ont/iot.owl#lastUpdated> "1534407204042"^^xsd:long ;
<http://orange-labs.fr/fog/ont/iot.owl#owner> "admin"^^xsd:string ;
<http://elite.polito.it/ontologies/dogont.owl#contains> <http://orange-labs.fr/thingin/tutorial#Sensor01> .
The metadata are here, the class and iri are right and we see the object property http://elite.polito.it/ontologies/dogont.owl#contains targeting the avatar with the iri http://orange-labs.fr/thingin/tutorial#Sensor01 a.k.a our sensor. For the very last time, make a read request on the sensor avatar, it will remain unchanged.
Object properties are unidirectionnal, when you perform a read request on an avatar, we always add the object properties starting from the avatar to the given payload in order to give you a complete avatar. In a semantic aspect, without mentionning the existence of the object property contains binding the living room to the sensor, the sensor is still complete. So this is fine.
Remember what i said about the Read-Mode and Read-Depth ? Let's perform a read depth on the living room
Read avatar with depth enabled
curl -X GET --header 'Accept: text/turtle' --header 'Read-Mode: depth' --header 'Read-Depth: 2' --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb21haW5zIjpbIiJdLCJqdGkiOiI0N2IyMDZkNC1hMTI3LTExZTgtODliOC1mYTE2M2VkMDk3N2UiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTUzNDQ5MTQ3MSwiaWF0IjoxNTM0NDA1MDcxLCJpc3MiOiJUaGluZ19pbiIsImV4dGVybmFsaWQiOiJhZG1pbiIsInNjb3BlcyI6WyJhZG1pbiJdLCJraWQiOiIwNzA3OWIyMS02OTllLTQ0NGYtOTA4Yi0xYTQzZjg4NzZhNDcifQ.ehMr5lECHJwLZ36aZEg93-3fZRq8cunJu3Z7F8ozWFs' 'http://api-dev-thingin.nprpaas.ddns.integ.dns-orange.fr/avatars/fde01614-3d34-432e-9e44-f52c491a2160'
See what i did with the Read-Mode and Read-Depth header, i activated the depth read mode and set the depth of the graph traversal to 2. It will return you something like this :
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://orange-labs.fr/thingin/tutorial#Sensor01>
a <http://elite.polito.it/ontologies/dogont.owl#SingleTemperatureSensor> ;
<http://orange-labs.fr/fog/ont/iot.owl#uuid> "d8d18e46-b04b-4b36-adbe-5b14172833e5"^^xsd:string ;
<http://orange-labs.fr/fog/ont/iot.owl#lastUpdated> "1534406158197"^^xsd:long .
<http://orange-labs.fr/thingin/tutorial#LivingRoom01>
a <http://elite.polito.it/ontologies/dogont.owl#LivingRoom> ;
<http://orange-labs.fr/fog/ont/iot.owl#uuid> "fde01614-3d34-432e-9e44-f52c491a2160"^^xsd:string ;
<http://orange-labs.fr/fog/ont/iot.owl#lastUpdated> "1534407204042"^^xsd:long ;
<http://orange-labs.fr/fog/ont/iot.owl#owner> "admin"^^xsd:string ;
<http://elite.polito.it/ontologies/dogont.owl#contains> <http://orange-labs.fr/thingin/tutorial#Sensor01> .
You could set the depth to 5, you won't have more than this because there are no data afterwards. Beware, this kind of request can be expensive if performed on supernode (avatar with thousands of object properties). We don't see the _depth in TURTLE, so do it again, but take data in JSON this time, and do it alone, to make sure you know how to use the header
{
"index": 0,
"items": [
{
"_depth": 1,
"_domain": null,
"_iri": "http://orange-labs.fr/thingin/tutorial#Sensor01",
"_last_updated": 1534406158197,
"_uuid": "d8d18e46-b04b-4b36-adbe-5b14172833e5",
"_static": false,
"_class": "http://elite.polito.it/ontologies/dogont.owl#SingleTemperatureSensor"
},
{
"_depth": 0,
"_domain": "http://orange-labs.fr/thingin/",
"_iri": "http://orange-labs.fr/thingin/tutorial#LivingRoom01",
"_last_updated": 1534407204042,
"_uuid": "fde01614-3d34-432e-9e44-f52c491a2160",
"_owner": "admin",
"_static": false,
"_outE": [
{
"_property": "http://elite.polito.it/ontologies/dogont.owl#contains",
"_uuid": "d8d18e46-b04b-4b36-adbe-5b14172833e5",
"_iri": "http://orange-labs.fr/thingin/tutorial#Sensor01"
}
],
"_class": "http://elite.polito.it/ontologies/dogont.owl#LivingRoom"
}
],
"page_size": 100,
"next": "http://10.226.225.229/avatars/fde01614-3d34-432e-9e44-f52c491a2160?index=100&page_size=100",
"size": 2
}
As you can see, _depth attribute in the sensor avatar is set to to 1
, it means we did one hop from the living room to reach the sensor. Fine.
We have an object property from the living room to the sensor, let's update the sensor with an equivalent of the http://elite.polito.it/ontologies/dogont.owl#contains object property : http://elite.polito.it/ontologies/dogont.owl#isIn :
@prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> .
@prefix gr: <http://purl.org/goodrelations/v1#> .
@prefix : <http://orange-labs.fr/thingin/tutorial#> .
:Sensor01
a dogont:SingleTemperatureSensor ;
gr:serialNumber "0001"^^xsd:string ;
dogont:isIn :LivingRoom01 .
Corresponding CURL update request :
curl -X PUT --header 'Content-Type: text/turtle' --header 'Accept: application/json' --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb21haW5zIjpbIiJdLCJqdGkiOiI0N2IyMDZkNC1hMTI3LTExZTgtODliOC1mYTE2M2VkMDk3N2UiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTUzNDQ5MTQ3MSwiaWF0IjoxNTM0NDA1MDcxLCJpc3MiOiJUaGluZ19pbiIsImV4dGVybmFsaWQiOiJhZG1pbiIsInNjb3BlcyI6WyJhZG1pbiJdLCJraWQiOiIwNzA3OWIyMS02OTllLTQ0NGYtOTA4Yi0xYTQzZjg4NzZhNDcifQ.ehMr5lECHJwLZ36aZEg93-3fZRq8cunJu3Z7F8ozWFs' -d '%40prefix dogont: <http://elite.polito.it/ontologies/dogont.owl#> . \
%40prefix gr: <http://purl.org/goodrelations/v1#> . \
%40prefix : <http://orange-labs.fr/thingin/tutorial#> . \
\
:Sensor01 \
a dogont:SingleTemperatureSensor ; \
gr:serialNumber "0001"^^xsd:string ; \
dogont:isIn :LivingRoom01 .' 'http://api-dev-thingin.nprpaas.ddns.integ.dns-orange.fr/avatars/update/set/d8d18e46-b04b-4b36-adbe-5b14172833e5'
Now, i'm sorry I lied to you, go read the sensor avatar once more , you should have the following :
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://orange-labs.fr/thingin/tutorial#Sensor01>
a <http://elite.polito.it/ontologies/dogont.owl#SingleTemperatureSensor> ;
<http://orange-labs.fr/fog/ont/iot.owl#uuid> "d8d18e46-b04b-4b36-adbe-5b14172833e5"^^xsd:string ;
<http://orange-labs.fr/fog/ont/iot.owl#lastUpdated> "1534419511177"^^xsd:long ;
<http://purl.org/goodrelations/v1#serialNumber> "0001"^^xsd:string ;
<http://elite.polito.it/ontologies/dogont.owl#isIn> <http://orange-labs.fr/thingin/tutorial#LivingRoom01> .
And because we are curious and patient, you can also perform the read depth from the sensor avatar (don't you complain, i already apologized to you !). It will look like this :
{
"index": 0,
"items": [
{
"_depth": 0,
"_domain": "http://orange-labs.fr/thingin/",
"_iri": "http://orange-labs.fr/thingin/tutorial#Sensor01",
"http://purl.org/goodrelations/v1#serialNumber": "0001",
"_last_updated": 1534419511177,
"_uuid": "d8d18e46-b04b-4b36-adbe-5b14172833e5",
"_static": false,
"_outE": [
{
"_property": "http://elite.polito.it/ontologies/dogont.owl#isIn",
"_uuid": "fde01614-3d34-432e-9e44-f52c491a2160",
"_iri": "http://orange-labs.fr/thingin/tutorial#LivingRoom01"
}
],
"_class": "http://elite.polito.it/ontologies/dogont.owl#SingleTemperatureSensor"
},
{
"_depth": 1,
"_domain": "http://orange-labs.fr/thingin/",
"_iri": "http://orange-labs.fr/thingin/tutorial#LivingRoom01",
"_last_updated": 1534407204042,
"_uuid": "fde01614-3d34-432e-9e44-f52c491a2160",
"_owner": "admin",
"_static": false,
"_outE": [
{
"_property": "http://elite.polito.it/ontologies/dogont.owl#contains",
"_uuid": "d8d18e46-b04b-4b36-adbe-5b14172833e5",
"_iri": "http://orange-labs.fr/thingin/tutorial#Sensor01"
}
],
"_class": "http://elite.polito.it/ontologies/dogont.owl#LivingRoom"
}
],
"page_size": 100,
"next": "http://10.226.225.229/avatars/d8d18e46-b04b-4b36-adbe-5b14172833e5?index=100&page_size=100",
"size": 2
}
We can, thanks to the new object property, perform traversal in both direction : from sensor to living room and from living room to sensor.
We want to remove the object property from the sensor, we could use an update unset for that, but instead, we will make some cleanup and delete the living room avatar. When you remove an avatar, you delete all of its properties, including all the edges (object properties) exiting and entering the avatar.
Delete avatar : Make sure it is the UUID OF THE LIVING ROOM before launching the request
curl -X DELETE --header 'Accept: application/json' --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb21haW5zIjpbIiJdLCJqdGkiOiI0N2IyMDZkNC1hMTI3LTExZTgtODliOC1mYTE2M2VkMDk3N2UiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTUzNDQ5MTQ3MSwiaWF0IjoxNTM0NDA1MDcxLCJpc3MiOiJUaGluZ19pbiIsImV4dGVybmFsaWQiOiJhZG1pbiIsInNjb3BlcyI6WyJhZG1pbiJdLCJraWQiOiIwNzA3OWIyMS02OTllLTQ0NGYtOTA4Yi0xYTQzZjg4NzZhNDcifQ.ehMr5lECHJwLZ36aZEg93-3fZRq8cunJu3Z7F8ozWFs' 'http://api-dev-thingin.nprpaas.ddns.integ.dns-orange.fr/avatars/fde01614-3d34-432e-9e44-f52c491a2160'
You should receive an empty body, with a 204 response code and some very basics response header, nothing specific to be seen here.
You know the drill right ? Come on, once more (Yes, go read the sensor avatar, in JSON or Turtle, i don't care)
{
"index": 0,
"items": [
{
"_depth": 0,
"_domain": "http://orange-labs.fr/thingin/",
"_iri": "http://orange-labs.fr/thingin/tutorial#Sensor01",
"http://purl.org/goodrelations/v1#serialNumber": "0001",
"_last_updated": 1534419511177,
"_uuid": "d8d18e46-b04b-4b36-adbe-5b14172833e5",
"_static": false,
"_class": "http://elite.polito.it/ontologies/dogont.owl#SingleTemperatureSensor"
}
],
"page_size": 100,
"next": "http://10.226.225.229/avatars/d8d18e46-b04b-4b36-adbe-5b14172833e5?index=100&page_size=100",
"size": 1
}
The object property ttp://elite.polito.it/ontologies/dogont.owl#isIn has been removed, everything is fine.
Through all of this tutorial, you've learned to create, read, update and delete avatar. I've refrain myself of any kind of cheats, so you should be able to do it all by yourselves.
Do not forget that if you need help finding the right ontologies and classes, you can select in the top bar : Explore > Explore Ontology Lookup Service to perform basic text search to find ontology classes. You can also go to Develop > OLS API reference to check in the API how to retrieve every object properties of a given ontology / class to see what is possible and what is note.
See you in part 2 to learn some useful stuff like doing batch requests to create, update and delete multiple avatars at once !