该客户端允许您连接 MyJohnDeere API,而无需编写自己的 oAuth 流程、API 请求和分页代码。
get
、 create
、 put
和delete
方法,以进行简单、经过身份验证的直接 API 调用each
、 map
等调用将根据需要获取新的数据页。 我们提供 RDoc 文档,但这里有一个有用的入门指南。由于 gem 名称很长,因此所有示例都将采用以下快捷方式:
JD = MyJohnDeereApi
所以当你看到:
JD :: Authorize
它的真正含义是:
MyJohnDeereApi :: Authorize
该库可作为 gem 使用。要使用它,只需安装 gem:
gem install my_john_deere_api
如果您正在使用 Bundler(为什么不呢?),那么将 gem 添加到您的 gemfile 中:
gem 'my_john_deere_api'
并运行:
bundle install
这是最简单的授权路径,尽管您的用户必须跳过向您提供验证码的额外环节:
# 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 )
实际上,当用户返回时,您可能需要重新实例化授权对象,并且这不会出现问题:
# 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 )
在网络应用程序中,您希望用户不必复制/粘贴验证码。所以你可以传入一个 :oauth_callback url。当用户通过 John Deere 授权您的应用程序时,他们将被重定向到您提供的 url,参数“oauth_verifier”包含验证码,因此用户无需提供验证码。
# 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 ] )
授权完成后, Client
对象将为该库提供大部分接口。客户端可以在有或没有用户凭据的情况下使用,因为某些 API 调用特定于您的应用程序与 John Deere 的关系,而不是您的用户的关系。但大多数交互都会涉及用户数据。以下是实例化客户端的方法:
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 ]
)
连接后,客户端的工作方式就像 ActiveRecord 的简化版本。来自 API 的 JSON 哈希值将转换为更易于使用的对象。事物的集合(例如组织)可以为您处理分页。只需使用each
、 map
等进行迭代,即可根据需要获取新页面。
该客户端正在开发中。您目前可以执行以下操作,而无需求助于 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
贡献产品集合就像一个列表。除了通过 Ruby 的 Enumerable Module 包含的所有方法之外,贡献产品集合还支持以下方法:
个人贡献产品支持以下方法和关联:
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
处理贡献产品的贡献定义。贡献定义集合支持以下方法:
个人贡献定义支持以下方法和关联:
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'
处理帐户的组织。组织集合支持以下方法:
单个组织支持以下方法和关联:
count
方法只需要加载第一页结果,因此这是一个相对便宜的调用。另一方面, all
强制从 John Deere 的 API 加载整个集合,因此请谨慎使用。无法通过 API 创建组织,因此此集合上没有create
方法。
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
处理组织的资产。资产集合支持以下方法:
单个资产支持以下方法和关联:
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
create
方法在 John Deere 平台中创建资产,并返回新创建的记录。
asset = organization . assets . create (
title : 'Asset Title' ,
asset_category : 'DEVICE' ,
asset_type : 'SENSOR' ,
asset_sub_type : 'ENVIRONMENTAL'
)
asset . title
# => 'Asset Title'
update
方法更新本地对象以及 John Deere 平台上的资产。只能更新资产的标题。
asset . update ( title : 'New Title' )
asset . title
# => 'New Title', also John Deere record is updated
save
方法使用已进行的任何本地更改来更新 John Deere。
asset . title = 'New Title'
asset . save
# => Successful Net::HTTPNoContent object
处理资产的位置。资产位置集合支持以下方法:
单个位置支持以下方法:
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"
# }
# ]
create
方法在 John Deere 平台中创建位置,并从 John Deere 返回新创建的对象。然而,由于没有生成唯一的ID,因此不会有新的信息。提交的时间戳(默认为“现在”)将四舍五入到最接近的秒。
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"
# }
# ]
不会更新或删除位置。最新的位置记录始终充当给定资产的状态,并且显示在地图视图上。
请注意,位置在 John Deere 中称为“资产位置”,但为了简洁起见,我们将关联称为“位置”,如asset.locations
中所示。
处理组织的领域。字段集合支持以下方法:
单个字段支持以下方法和关联:
count
方法只需要加载第一页结果,因此这是一个相对便宜的调用。另一方面, all
强制从 John Deere 的 API 加载整个集合,因此请谨慎使用。可以通过 API 创建字段,但该集合还没有create
方法。
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
处理字段的标志。标志集合支持以下方法。请注意,John Deere 不提供通过 id 检索特定标志的端点:
单个标志支持以下方法和关联:
count
方法只需要加载第一页结果,因此这是一个相对便宜的调用。另一方面, all
强制从 John Deere 的 API 加载整个集合,因此请谨慎使用。可以通过 API 创建标志,但该集合还没有create
方法。
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
虽然客户端的目标是消除对 John Deere API 进行/解释调用的需要,但能够进行客户端尚未完全支持的调用也很重要。或者有时,您需要排除故障。
GET 请求仅需要资源路径。
client . get ( '/organizations' )
简短的响应示例:
{
"links" : [ " ... " ],
"total" : 1 ,
"values" : [
{
"@type" : " Organization " ,
"name" : " ABC Farms " ,
"type" : " customer " ,
"member" : true ,
"id" : " 123123 " ,
"links" : [ " ... " ]
}
]
}
这不会提供任何客户端功能,例如分页或验证,但它会解析返回的 JSON。
POST 请求需要资源路径和请求正文的哈希值。客户端将对密钥进行驼峰化,然后转换为 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"
}
]
}
)
John Deere 的标准响应是 201 HTTP 状态代码,并带有消息“已创建”。此方法返回完整的 Net::HTTP 响应。
PUT 请求需要资源路径和请求正文的哈希值。客户端将对密钥进行驼峰化,然后转换为 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"
}
]
}
)
John Deere 的标准响应是 204 HTTP 状态代码,并带有消息“No Content”。此方法返回完整的 Net::HTTP 响应。
DELETE 请求仅需要资源路径。
client . delete ( '/assets/123123' )
John Deere 的标准响应是 204 HTTP 状态代码,并带有消息“No Content”。此方法返回完整的 Net::HTTP 响应。
自定义错误有助于清楚地识别使用客户端时出现的问题:
:sandbox
或:production
。在 GitHub 上为这颗宝石加注星标。它可以帮助开发人员找到并选择这个宝石,而不是其他可能存在的宝石。据我们所知,没有其他约翰迪尔宝石正在积极维护。
最简单的贡献方式是:
vcr_setup
中vcr_setup
中。