Ce client vous permet de connecter l'API MyJohnDeere sans avoir à coder votre propre processus oAuth, vos requêtes API et votre pagination.
get
, create
, put
et delete
pour effectuer des appels API simples, authentifiés et directseach
, map
, etc. récupéreront de nouvelles pages de données selon les besoins. Nous fournissons de la documentation RDoc, mais voici un guide utile pour commencer. Le nom de la gemme étant long, tous les exemples utiliseront ce raccourci :
JD = MyJohnDeereApi
De sorte que lorsque vous voyez :
JD :: Authorize
Cela signifie en réalité :
MyJohnDeereApi :: Authorize
Cette bibliothèque est disponible sous forme de joyau. Pour l'utiliser, installez simplement la gem :
gem install my_john_deere_api
Si vous utilisez Bundler (et pourquoi pas ?), ajoutez la gemme à votre fichier gem :
gem 'my_john_deere_api'
et exécutez :
bundle install
Il s'agit du chemin le plus simple vers l'autorisation, même si votre utilisateur doit franchir une étape supplémentaire pour vous fournir le code de vérification :
# Create an authorize object, using your app's API key and secret. You can
# pass an environment (`:live` or `:sandbox`), which default to `:live`.
authorize = JD :: Authorize . new ( API_KEY , API_SECRET , environment : :sandbox )
# Retrieve a valid authorization url from John Deere, where you can send
# your user for authorizing your app to the JD platform.
url = authorize . authorize_url
# Verify the code given to the user during the authorization process, and
# turn this into access credentials for your user.
authorize . verify ( code )
En réalité, vous devrez probablement ré-instancier l'objet d'autorisation au retour de l'utilisateur, et cela fonctionne sans problème :
# Create an authorize object, using your app's API key and secret.
authorize = JD :: Authorize . new ( API_KEY , API_SECRET , environment : :sandbox )
# Retrieve a valid authorization url from John Deere.
url = authorize . authorize_url
# Queue elevator music while your app serves other users...
# Re-create the authorize instance in a different process
authorize = JD :: Authorize . new ( API_KEY , API_SECRET , environment : :sandbox )
# Proceed as normal
authorize . verify ( code )
Dans une application Web, vous préférez que votre utilisateur n'ait pas à copier/coller les codes de vérification. Vous pouvez donc transmettre une URL :oauth_callback. Lorsque l'utilisateur autorise votre application auprès de John Deere, il est redirigé vers l'url que vous fournissez, avec le paramètre « oauth_verifier » qui contient le code de vérification afin que l'utilisateur n'ait pas à le fournir.
# Create an authorize object, using your app's API key and secret.
authorize = JD :: Authorize . new (
API_KEY ,
API_SECRET ,
environment : :sandbox ,
oauth_callback : 'https://example.com'
)
# Retrieve a valid authorization url from John Deere.
# This will contain the callback url encoded into the
# query string for you.
url = authorize . authorize_url
# Queue elevator music while your app serves other users...
# Re-create the authorize instance in a different process.
# It's not necessary to re-initialize with the callback url.
authorize = JD :: Authorize . new ( API_KEY , API_SECRET , environment : :sandbox )
# Inside a Rails controller, you might do this:
authorize . verify ( params [ :oauth_verifier ] )
Une fois l'autorisation terminée, l'objet Client
fournira la majeure partie de l'interface de cette bibliothèque. Un client peut être utilisé avec ou sans informations d'identification utilisateur, car certains appels d'API sont spécifiques à la relation de votre application avec John Deere, et non à celle de votre utilisateur. Mais la plupart des interactions impliqueront des données utilisateur. Voici comment instancier un client :
client = JD :: Client . new (
# the application's API key
API_KEY ,
# the application's API secret
API_SECRET ,
# the chosen environment (:sandbox or :live)
environment : :sandbox ,
# optional contribution_definition_id. This is needed for some requests,
# but the client can be created without it, in order to find it.
contribution_definition_id : CONTRIBUTION_DEFINITION_ID ,
# the user's access credentials
access : [ ACCESS_TOKEN , ACCESS_SECRET ]
)
Une fois connecté, le client fonctionne comme une version simplifiée d'ActiveRecord. Les hachages JSON de l'API sont convertis en objets pour faciliter l'utilisation. Les collections d'éléments, comme les organisations, gèrent la pagination pour vous. Itérez simplement en utilisant each
, map
, etc., et de nouvelles pages sont récupérées selon les besoins.
Ce client est un travail en cours. Vous pouvez actuellement effectuer les opérations suivantes sans recourir aux appels d'API :
client
├── contribution_products
| ├── count
| ├── all
| ├── first
| └── find(contribution_product_id)
| └── contribution_definitions
| ├── count
| ├── all
| ├── first
| └── find(contribution_definition_id)
└── organizations
├── count
├── all
├── first
└── find(organization_id)
├── assets(attributes)
| ├── create(attributes)
| ├── count
| ├── all
| ├── first
| └── find(asset_id)
| ├── save
| ├── update(attributes)
| └── locations
| ├── create(attributes)
| ├── count
| ├── all
| └── first
└── fields
├── count
├── all
├── first
└── find(field_id)
└── flags
├── count
├── all
└── first
Les collections de produits de contribution agissent comme une liste. En plus de toutes les méthodes incluses via le module Enumerable de Ruby, les collections de produits de contribution prennent en charge les méthodes suivantes :
Un produit de contribution individuelle prend en charge les méthodes et associations suivantes :
client . contribution_products
# => collection of contribution products under this client
client . contribution_products . count
# => 1
client . contribution_products . first
# => an individual contribution product
contribution_product = client . contribution_products . find ( 1234 )
# => an individual contribution product, fetched by ID
contribution_product . market_place_name
# => 'Market Place Name'
contribution_product . contribution_definitions
# => collection of contribution definitions belonging to this contribution product
Gère les définitions de contribution d’un produit de contribution. Les collections de définitions de contribution prennent en charge les méthodes suivantes :
Une définition de contribution individuelle prend en charge les méthodes et associations suivantes :
contribution_product . contribution_definitions
# => collection of contribution definitions under this contribution product
client . contribution_definitions . count
# => 1
client . contribution_definitions . first
# => an individual contribution definition
contribution_definition = contribution_product . contribution_definitions . find ( 1234 )
# => an individual contribution definition, fetched by ID
contribution_definition . name
# => 'Contribution Definition Name'
Gère les organisations d’un compte. Les collections d’organisation prennent en charge les méthodes suivantes :
Une organisation individuelle prend en charge les méthodes et associations suivantes :
La méthode count
nécessite uniquement le chargement de la première page de résultats, c'est donc un appel relativement bon marché. D'un autre côté, all
force le chargement de l'intégralité de la collection à partir de l'API de John Deere, donc à utiliser avec prudence. Les organisations ne peuvent pas être créées via l'API, il n'y a donc pas de méthode create
sur cette collection.
client . organizations
# => collection of organizations under this client
client . organizations . count
# => 15
client . organizations . first
# => an individual organization object
organization = client . organizations . find ( 1234 )
# => an individual organization object, fetched by ID
organization . name
# => 'Smith Farms'
organization . type
# => 'customer'
organization . member?
# => true
organization . links
# => {
# 'self' => 'https://sandboxapi.deere.com/platform/organizations/1234',
# 'machines' => 'https://sandboxapi.deere.com/platform/organizations/1234/machines',
# 'wdtCapableMachines' => 'https://sandboxapi.deere.com/platform/organizations/1234/machines?capability=wdt'
# }
organization . assets
# => collection of assets belonging to this organization
organization . fields
# => collection of fields belonging to this organization
Gère les actifs d’une organisation. Les collections d'actifs prennent en charge les méthodes suivantes :
Un actif individuel prend en charge les méthodes et associations suivantes :
organization = client . organizations . first
# => the first organization returned by the client
organization . assets
# => collection of assets belonging to this organization
asset = organization . assets . find ( 123 )
# => an individual asset object, fetched by ID
asset . title
# => 'AgThing Water Device'
asset . category
# => 'DEVICE'
asset . type
# => 'SENSOR'
asset . sub_type
# => 'OTHER'
asset . links
# => a hash of API urls related to this asset
La méthode create
crée l'actif sur la plateforme John Deere et renvoie l'enregistrement nouvellement créé.
asset = organization . assets . create (
title : 'Asset Title' ,
asset_category : 'DEVICE' ,
asset_type : 'SENSOR' ,
asset_sub_type : 'ENVIRONMENTAL'
)
asset . title
# => 'Asset Title'
La méthode update
met à jour l'objet local, ainsi que l'actif sur la plateforme John Deere. Seul le titre d'un bien peut être mis à jour.
asset . update ( title : 'New Title' )
asset . title
# => 'New Title', also John Deere record is updated
La méthode save
met à jour John Deere avec toutes les modifications locales apportées.
asset . title = 'New Title'
asset . save
# => Successful Net::HTTPNoContent object
Gère les emplacements d’un actif. Les collections d'emplacements d'actifs prennent en charge les méthodes suivantes :
Un emplacement individuel prend en charge les méthodes suivantes :
asset = organizations . assets . first
# => the first asset returned by the organization
asset . locations
# => collection of locations belonging to this asset
location = asset . locations . first
# => the first location returned by the asset. Note that locations do not have their own id's
# in the JD platform, and therefore cannot be requested individually via a "find" method.
location . timestamp
# => "2019-11-11T23:00:00.000Z"
# John Deere includes 3 decimal places in the format, but does not actually
# store fractions of a second, so it will always end in ".000". This is
# important, because timestamps must be unique.
location . geometry
# => a GeoJSON formatted hash, for example:
# {
# "type"=>"Feature",
# "geometry"=>{
# "geometries"=>[
# {
# "coordinates"=>[-95.123456, 40.123456],
# "type"=>"Point"
# }
# ],
# "type"=>"GeometryCollection"
# }
# }
location . measurement_data
# => the status details of this location, for example:
# [
# {
# "@type"=>"BasicMeasurement",
# "name"=>"[Soil Temperature](http://example.com/current_temperature)",
# "value"=>"21.0",
# "unit"=>"°C"
# }
# ]
La méthode create
crée l'emplacement sur la plate-forme John Deere et renvoie l'objet nouvellement créé depuis John Deere. Cependant, il n’y aura aucune nouvelle information puisqu’aucun identifiant unique n’est généré. L'horodatage soumis (qui est par défaut « maintenant ») sera arrondi à la seconde la plus proche.
locaton = asset . locatons . create (
# You can pass fractional seconds, but they will be truncated by JD.
timestamp : "2019-11-11T23:00:00.123Z" ,
# JD requires more complicated JSON geometry, but this client will convert a simple
# set of lat/long coordinates into the larger format automatically.
geometry : [ - 95.123456 , 40.123456 ] ,
# This is a list of "measurements"
measurement_data : [
{
name : 'Temperature' ,
value : '68.0' ,
unit : 'F'
}
]
)
location . timestamp
# => "2019-11-11T23:00:00.000Z"
# Note that the timestamp's fractional second is truncated by John Deere, though they
# still return the record with three digits of precision.
location . geometry
# => a GeoJSON formatted hash in its larger format
# {
# "type"=>"Feature",
# "geometry"=>{
# "geometries"=>[
# {
# "coordinates"=>[-95.123456, 40.123456],
# "type"=>"Point"
# }
# ],
# "type"=>"GeometryCollection"
# }
# }
location . measurement_data
# [
# {
# "@type"=>"BasicMeasurement",
# "name"=>"Temperature",
# "value"=>"68.0",
# "unit"=>"F"
# }
# ]
Il n'y a pas de mise à jour ou de suppression d'un emplacement. L'enregistrement de localisation le plus récent fait toujours office de statut pour l'actif donné et est ce qui apparaît sur la vue cartographique.
Notez que les emplacements sont appelés « Asset Locations » dans John Deere, mais nous appelons l'association « locations », comme dans asset.locations
, par souci de concision.
Gère les champs d’une organisation. Les collections de champs prennent en charge les méthodes suivantes :
Un champ individuel prend en charge les méthodes et associations suivantes :
La méthode count
nécessite uniquement le chargement de la première page de résultats, c'est donc un appel relativement bon marché. D'un autre côté, all
force le chargement de l'intégralité de la collection à partir de l'API de John Deere, donc à utiliser avec prudence. Les champs peuvent être créés via l'API, mais il n'existe pas encore de méthode create
sur cette collection.
organization . fields
# => collection of fields under this organization
organization . fields . count
# => 15
organization . fields . first
# => an individual field object
field = organization . fields . find ( 1234 )
# => an individual field object, fetched by ID
field . name
# => 'Smith Field'
field . archived?
# => false
field . links
# => a hash of API urls related to this field
field . flags
# => collection of flags belonging to this field
Gère les drapeaux d'un champ. Les collections d’indicateurs prennent en charge les méthodes suivantes. Notez que John Deere ne fournit pas de point final pour récupérer un indicateur spécifique par identifiant :
Un indicateur individuel prend en charge les méthodes et associations suivantes :
La méthode count
nécessite uniquement le chargement de la première page de résultats, c'est donc un appel relativement bon marché. D'un autre côté, all
force le chargement de l'intégralité de la collection à partir de l'API de John Deere, donc à utiliser avec prudence. Les indicateurs peuvent être créés via l'API, mais il n'existe pas encore de méthode create
sur cette collection.
field . flags
# => collection of flags under this field
field . flags . count
# => 15
flag = field . flags . first
# => an individual flag object
flag . notes
# => 'A big rock on the left after entering the field'
flag . geometry
# => a GeoJSON formatted hash, for example:
# {
# "type"=>"Feature",
# "geometry"=>{
# "geometries"=>[
# {
# "coordinates"=>[-95.123456, 40.123456],
# "type"=>"Point"
# }
# ],
# "type"=>"GeometryCollection"
# }
# }
field . archived?
# => false
field . proximity_alert_enabled?
# => true
field . links
# => a hash of API urls related to this flag
Même si l'objectif du client est d'éliminer le besoin d'effectuer/interpréter des appels vers l'API John Deere, il est important de pouvoir effectuer des appels qui ne sont pas encore entièrement pris en charge par le client. Ou parfois, vous devez dépanner.
Les requêtes GET nécessitent uniquement un chemin de ressource.
client . get ( '/organizations' )
Exemple de réponse abrégée :
{
"links" : [ " ... " ],
"total" : 1 ,
"values" : [
{
"@type" : " Organization " ,
"name" : " ABC Farms " ,
"type" : " customer " ,
"member" : true ,
"id" : " 123123 " ,
"links" : [ " ... " ]
}
]
}
Cela ne fournira aucun avantage client comme la pagination ou la validation, mais il analysera le JSON renvoyé.
Les requêtes POST nécessitent un chemin de ressource et un hachage pour le corps de la requête. Le client camélisera les clés et les convertira en JSON.
client . post (
'/organizations/123123/assets' ,
{
"title" => "i like turtles" ,
"assetCategory" => "DEVICE" ,
"assetType" => "SENSOR" ,
"assetSubType" => "ENVIRONMENTAL" ,
"links" => [
{
"@type" => "Link" ,
"rel" => "contributionDefinition" ,
"uri" => "https://sandboxapi.deere.com/platform/contributionDefinitions/CONTRIBUTION_DEFINITION_ID"
}
]
}
)
La réponse standard de John Deere est un code d'état HTTP 201, avec le message « Créé ». Cette méthode renvoie la réponse Net::HTTP complète.
Les requêtes PUT nécessitent un chemin de ressource et un hachage pour le corps de la requête. Le client camélisera les clés et les convertira en JSON.
client . put (
'/assets/123123' ,
{
"title" => "i REALLY like turtles" ,
"assetCategory" => "DEVICE" ,
"assetType" => "SENSOR" ,
"assetSubType" => "ENVIRONMENTAL" ,
"links" => [
{
"@type" => "Link" ,
"rel" => "contributionDefinition" ,
"uri" => "https://sandboxapi.deere.com/platform/contributionDefinitions/CONTRIBUTION_DEFINITION_ID"
}
]
}
)
La réponse standard de John Deere est un code d'état HTTP 204, avec le message « No Content ». Cette méthode renvoie la réponse Net::HTTP complète.
Les requêtes DELETE nécessitent uniquement un chemin de ressource.
client . delete ( '/assets/123123' )
La réponse standard de John Deere est un code d'état HTTP 204, avec le message « No Content ». Cette méthode renvoie la réponse Net::HTTP complète.
Les erreurs personnalisées permettent d'identifier clairement les problèmes lors de l'utilisation du client :
:sandbox
ou :production
.Mettez ce joyau en vedette sur GitHub. Cela aide les développeurs à trouver et à choisir ce joyau parmi d’autres qui pourraient exister. À notre connaissance, aucun autre joyau John Deere n’est activement entretenu.
La façon la plus simple de contribuer est :
vcr_setup
vcr_setup
.