my_john_deere_api 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +813 -0
- data/Rakefile +9 -0
- data/lib/my_john_deere_api.rb +17 -0
- data/lib/my_john_deere_api/authorize.rb +69 -0
- data/lib/my_john_deere_api/client.rb +151 -0
- data/lib/my_john_deere_api/consumer.rb +90 -0
- data/lib/my_john_deere_api/errors.rb +7 -0
- data/lib/my_john_deere_api/errors/invalid_record_error.rb +29 -0
- data/lib/my_john_deere_api/errors/missing_contribution_definition_id_error.rb +12 -0
- data/lib/my_john_deere_api/errors/not_yet_implemented_error.rb +12 -0
- data/lib/my_john_deere_api/errors/type_mismatch_error.rb +12 -0
- data/lib/my_john_deere_api/errors/unsupported_environment_error.rb +18 -0
- data/lib/my_john_deere_api/helpers.rb +6 -0
- data/lib/my_john_deere_api/helpers/case_conversion.rb +37 -0
- data/lib/my_john_deere_api/helpers/environment_helper.rb +25 -0
- data/lib/my_john_deere_api/helpers/uri_helpers.rb +19 -0
- data/lib/my_john_deere_api/helpers/validate_contribution_definition.rb +18 -0
- data/lib/my_john_deere_api/model.rb +10 -0
- data/lib/my_john_deere_api/model/asset.rb +69 -0
- data/lib/my_john_deere_api/model/asset_location.rb +19 -0
- data/lib/my_john_deere_api/model/base.rb +97 -0
- data/lib/my_john_deere_api/model/contribution_definition.rb +15 -0
- data/lib/my_john_deere_api/model/contribution_product.rb +33 -0
- data/lib/my_john_deere_api/model/field.rb +40 -0
- data/lib/my_john_deere_api/model/flag.rb +36 -0
- data/lib/my_john_deere_api/model/organization.rb +43 -0
- data/lib/my_john_deere_api/net_http_retry.rb +2 -0
- data/lib/my_john_deere_api/net_http_retry/decorator.rb +53 -0
- data/lib/my_john_deere_api/net_http_retry/max_retries_exceeded_error.rb +20 -0
- data/lib/my_john_deere_api/request.rb +6 -0
- data/lib/my_john_deere_api/request/collection.rb +10 -0
- data/lib/my_john_deere_api/request/collection/asset_locations.rb +27 -0
- data/lib/my_john_deere_api/request/collection/assets.rb +34 -0
- data/lib/my_john_deere_api/request/collection/base.rb +91 -0
- data/lib/my_john_deere_api/request/collection/contribution_definitions.rb +26 -0
- data/lib/my_john_deere_api/request/collection/contribution_products.rb +26 -0
- data/lib/my_john_deere_api/request/collection/fields.rb +26 -0
- data/lib/my_john_deere_api/request/collection/flags.rb +33 -0
- data/lib/my_john_deere_api/request/collection/organizations.rb +26 -0
- data/lib/my_john_deere_api/request/create.rb +5 -0
- data/lib/my_john_deere_api/request/create/asset.rb +57 -0
- data/lib/my_john_deere_api/request/create/asset_location.rb +110 -0
- data/lib/my_john_deere_api/request/create/base.rb +67 -0
- data/lib/my_john_deere_api/request/individual.rb +8 -0
- data/lib/my_john_deere_api/request/individual/asset.rb +19 -0
- data/lib/my_john_deere_api/request/individual/base.rb +52 -0
- data/lib/my_john_deere_api/request/individual/contribution_definition.rb +19 -0
- data/lib/my_john_deere_api/request/individual/contribution_product.rb +19 -0
- data/lib/my_john_deere_api/request/individual/field.rb +19 -0
- data/lib/my_john_deere_api/request/individual/organization.rb +19 -0
- data/lib/my_john_deere_api/request/update.rb +4 -0
- data/lib/my_john_deere_api/request/update/asset.rb +40 -0
- data/lib/my_john_deere_api/request/update/base.rb +67 -0
- data/lib/my_john_deere_api/validators.rb +5 -0
- data/lib/my_john_deere_api/validators/asset.rb +35 -0
- data/lib/my_john_deere_api/validators/asset_location.rb +34 -0
- data/lib/my_john_deere_api/validators/base.rb +67 -0
- data/lib/my_john_deere_api/version.rb +3 -0
- data/test/lib/my_john_deere_api/authorize_test.rb +81 -0
- data/test/lib/my_john_deere_api/client_test.rb +225 -0
- data/test/lib/my_john_deere_api/consumer_test.rb +58 -0
- data/test/lib/my_john_deere_api/errors/invalid_record_error_test.rb +26 -0
- data/test/lib/my_john_deere_api/errors/max_retries_exceeded_error_test.rb +13 -0
- data/test/lib/my_john_deere_api/errors/missing_contribution_definition_id_error_test.rb +14 -0
- data/test/lib/my_john_deere_api/errors/not_yet_implemented_error_test.rb +13 -0
- data/test/lib/my_john_deere_api/errors/type_mismatch_error_test.rb +13 -0
- data/test/lib/my_john_deere_api/errors/unsupported_environment_error_test.rb +18 -0
- data/test/lib/my_john_deere_api/errors_test.rb +25 -0
- data/test/lib/my_john_deere_api/helpers/case_conversion_test.rb +100 -0
- data/test/lib/my_john_deere_api/helpers/environment_helper_test.rb +67 -0
- data/test/lib/my_john_deere_api/helpers/uri_helpers_test.rb +58 -0
- data/test/lib/my_john_deere_api/helpers/validate_contribution_definition_test.rb +74 -0
- data/test/lib/my_john_deere_api/helpers_test.rb +21 -0
- data/test/lib/my_john_deere_api/model/asset_location_test.rb +38 -0
- data/test/lib/my_john_deere_api/model/asset_test.rb +133 -0
- data/test/lib/my_john_deere_api/model/base_test.rb +76 -0
- data/test/lib/my_john_deere_api/model/contribution_definition_test.rb +52 -0
- data/test/lib/my_john_deere_api/model/contribution_product_test.rb +82 -0
- data/test/lib/my_john_deere_api/model/field_test.rb +65 -0
- data/test/lib/my_john_deere_api/model/flag_test.rb +48 -0
- data/test/lib/my_john_deere_api/model/organization_test.rb +84 -0
- data/test/lib/my_john_deere_api/model_test.rb +37 -0
- data/test/lib/my_john_deere_api/net_http_retry/decorator_test.rb +163 -0
- data/test/lib/my_john_deere_api/request/collection/asset_locations_test.rb +102 -0
- data/test/lib/my_john_deere_api/request/collection/assets_test.rb +99 -0
- data/test/lib/my_john_deere_api/request/collection/base_test.rb +27 -0
- data/test/lib/my_john_deere_api/request/collection/contribution_definitions_test.rb +88 -0
- data/test/lib/my_john_deere_api/request/collection/contribution_products_test.rb +88 -0
- data/test/lib/my_john_deere_api/request/collection/fields_test.rb +86 -0
- data/test/lib/my_john_deere_api/request/collection/flags_test.rb +92 -0
- data/test/lib/my_john_deere_api/request/collection/organizations_test.rb +87 -0
- data/test/lib/my_john_deere_api/request/collection_test.rb +37 -0
- data/test/lib/my_john_deere_api/request/create/asset_location_test.rb +163 -0
- data/test/lib/my_john_deere_api/request/create/asset_test.rb +182 -0
- data/test/lib/my_john_deere_api/request/create/base_test.rb +29 -0
- data/test/lib/my_john_deere_api/request/create_test.rb +17 -0
- data/test/lib/my_john_deere_api/request/individual/asset_test.rb +33 -0
- data/test/lib/my_john_deere_api/request/individual/base_test.rb +18 -0
- data/test/lib/my_john_deere_api/request/individual/contribution_definition_test.rb +33 -0
- data/test/lib/my_john_deere_api/request/individual/contribution_product_test.rb +33 -0
- data/test/lib/my_john_deere_api/request/individual/field_test.rb +37 -0
- data/test/lib/my_john_deere_api/request/individual/organization_test.rb +33 -0
- data/test/lib/my_john_deere_api/request/individual_test.rb +29 -0
- data/test/lib/my_john_deere_api/request/update/asset_test.rb +99 -0
- data/test/lib/my_john_deere_api/request/update/base_test.rb +60 -0
- data/test/lib/my_john_deere_api/request/update_test.rb +13 -0
- data/test/lib/my_john_deere_api/request_test.rb +21 -0
- data/test/lib/my_john_deere_api/validators/asset_location_test.rb +61 -0
- data/test/lib/my_john_deere_api/validators/asset_test.rb +93 -0
- data/test/lib/my_john_deere_api/validators/base_test.rb +92 -0
- data/test/lib/my_john_deere_api/validators_test.rb +17 -0
- data/test/lib/my_john_deere_api/version_test.rb +9 -0
- data/test/my_john_deere_api_test.rb +37 -0
- data/test/support/helper.rb +97 -0
- data/test/support/vcr/accessor/delete_failed.yml +327 -0
- data/test/support/vcr/accessor/delete_max_failed.yml +615 -0
- data/test/support/vcr/accessor/delete_retry.yml +191 -0
- data/test/support/vcr/accessor/delete_retry_too_soon.yml +191 -0
- data/test/support/vcr/accessor/get_failed.yml +390 -0
- data/test/support/vcr/accessor/get_max_failed.yml +734 -0
- data/test/support/vcr/accessor/get_retry.yml +226 -0
- data/test/support/vcr/accessor/get_retry_too_soon.yml +226 -0
- data/test/support/vcr/accessor/post_failed.yml +417 -0
- data/test/support/vcr/accessor/post_max_failed.yml +785 -0
- data/test/support/vcr/accessor/post_retry.yml +241 -0
- data/test/support/vcr/accessor/post_retry_too_soon.yml +241 -0
- data/test/support/vcr/accessor/put_failed.yml +372 -0
- data/test/support/vcr/accessor/put_max_failed.yml +700 -0
- data/test/support/vcr/accessor/put_retry.yml +216 -0
- data/test/support/vcr/accessor/put_retry_too_soon.yml +216 -0
- data/test/support/vcr/catalog.yml +89 -0
- data/test/support/vcr/delete_asset.yml +82 -0
- data/test/support/vcr/get_access_token.yml +41 -0
- data/test/support/vcr/get_asset.yml +144 -0
- data/test/support/vcr/get_asset_locations.yml +196 -0
- data/test/support/vcr/get_assets.yml +152 -0
- data/test/support/vcr/get_contribution_definition.yml +90 -0
- data/test/support/vcr/get_contribution_definitions.yml +91 -0
- data/test/support/vcr/get_contribution_product.yml +91 -0
- data/test/support/vcr/get_contribution_products.yml +91 -0
- data/test/support/vcr/get_field.yml +144 -0
- data/test/support/vcr/get_fields.yml +146 -0
- data/test/support/vcr/get_flags.yml +47 -0
- data/test/support/vcr/get_organization.yml +90 -0
- data/test/support/vcr/get_organizations.yml +149 -0
- data/test/support/vcr/get_request_token.yml +83 -0
- data/test/support/vcr/post_asset_locations.yml +244 -0
- data/test/support/vcr/post_assets.yml +192 -0
- data/test/support/vcr/put_asset.yml +87 -0
- data/test/support/vcr/warning.txt +28 -0
- data/test/support/vcr_setup.rb +488 -0
- metadata +277 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 75b86b9b093f4aa0cc586ce56fb961654b1b91577947acf48392d8d2294c85b9
|
4
|
+
data.tar.gz: b5879b20c85891180747ba42657ffa399da981596820c813a7049d680240dd39
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6a8c729311baa853f8ae1039573f673cb01cc084d0fc9b662ce592dd1b907a85b153f04d07ebd6bf346558efb708242f5c13f3464f3c4c5b03a4c21a2479c2d9
|
7
|
+
data.tar.gz: cf5dd0b1e590baeb06ead7ffeffb4a7501de17b8b56596a297797186f1bc85aa33b196f58f19162f6027e40a27b023f9ad18ad3aa25e07b61fcd383612c0bbaa
|
data/README.md
ADDED
@@ -0,0 +1,813 @@
|
|
1
|
+
# Ruby Client for the MyJohnDeere API
|
2
|
+
|
3
|
+
[](https://circleci.com/gh/Intellifarm/my_john_deere_api)
|
4
|
+
|
5
|
+
This client allows you to connect the [MyJohnDeere API](https://developer.deere.com/#!documentation)
|
6
|
+
without having to code your own oAuth process, API requests, and pagination.
|
7
|
+
|
8
|
+
* Works with Rails, but does not require it
|
9
|
+
* Supports both sandbox and live mode
|
10
|
+
* Simplifies the oAuth negotiation process
|
11
|
+
* Provides an ActiveRecord-style interface to many endpoints
|
12
|
+
* Provides `get`, `create`, `put`, and `delete` methods to make easy, authenticated, direct API calls
|
13
|
+
* Uses ruby enumerables to handle pagination behind the scenes. Calls like `each`, `map`, etc will fetch new pages of data as needed.
|
14
|
+
|
15
|
+
## Table of Contents
|
16
|
+
|
17
|
+
* [How to Read This Documentation](#how-to-read-this-documentation)
|
18
|
+
* [Installation](#installation)
|
19
|
+
* [Authorizing with John Deere via oAuth 1.0](#authorizing-with-john-deere-via-oauth-10)
|
20
|
+
* [Interacting with the User's John Deere Account](#interacting-with-the-users-john-deere-account)
|
21
|
+
* [Using the Client to Do Stuff](#using-the-client-to-do-stuff)
|
22
|
+
* [Contribution Products](#contribution-products)
|
23
|
+
* [Contribution Definitions](#contribution-definitions)
|
24
|
+
* [Organizations](#organizations)
|
25
|
+
* [Assets](#assets)
|
26
|
+
* [Asset Locations](#asset-locations)
|
27
|
+
* [Fields](#fields)
|
28
|
+
* [Direct API Requests](#direct-api-requests)
|
29
|
+
* [GET](#get)
|
30
|
+
* [POST](#post)
|
31
|
+
* [PUT](#put)
|
32
|
+
* [DELETE](#delete)
|
33
|
+
* [Errors](#errors)
|
34
|
+
* [How Can I Help?](#how-can-i-help)
|
35
|
+
* [Give Us a Star!](#give-us-a-star)
|
36
|
+
* [Contribute to This Gem](#contribute-to-this-gem)
|
37
|
+
|
38
|
+
|
39
|
+
## How To Read This Documentation
|
40
|
+
|
41
|
+
We provide RDoc documentation, but here is a helpful guide for getting started. Because the gem name is long, all examples are going
|
42
|
+
to assume this shortcut:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
JD = MyJohnDeereApi
|
46
|
+
```
|
47
|
+
|
48
|
+
So that when you see:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
JD::Authorize
|
52
|
+
```
|
53
|
+
It really means:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
MyJohnDeereApi::Authorize
|
57
|
+
```
|
58
|
+
|
59
|
+
|
60
|
+
## Installation
|
61
|
+
|
62
|
+
This library is available as a gem. To use it, just install the gem:
|
63
|
+
|
64
|
+
```bash
|
65
|
+
gem install my_john_deere_api
|
66
|
+
```
|
67
|
+
|
68
|
+
If you're using [Bundler](https://bundler.io/) (and why wouldn't you?) then add the gem to your gemfile:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
gem 'my_john_deere_api'
|
72
|
+
```
|
73
|
+
|
74
|
+
and run:
|
75
|
+
|
76
|
+
```bash
|
77
|
+
bundle install
|
78
|
+
```
|
79
|
+
|
80
|
+
|
81
|
+
## Authorizing with John Deere via oAuth 1.0
|
82
|
+
|
83
|
+
This is the simplest path to authorization, though your user has to jump through an extra hoop of giving you the verification code:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
# Create an authorize object, using your app's API key and secret. You can
|
87
|
+
# pass an environment (`:live` or `:sandbox`), which default to `:live`.
|
88
|
+
authorize = JD::Authorize.new(API_KEY, API_SECRET, environment: :sandbox)
|
89
|
+
|
90
|
+
# Retrieve a valid authorization url from John Deere, where you can send
|
91
|
+
# your user for authorizing your app to the JD platform.
|
92
|
+
url = authorize.authorize_url
|
93
|
+
|
94
|
+
# Verify the code given to the user during the authorization process, and
|
95
|
+
# turn this into access credentials for your user.
|
96
|
+
authorize.verify(code)
|
97
|
+
```
|
98
|
+
|
99
|
+
In reality, you will likely need to re-instantiate the authorize object when the user returns, and that works without issue:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
# Create an authorize object, using your app's API key and secret.
|
103
|
+
authorize = JD::Authorize.new(API_KEY, API_SECRET, environment: :sandbox)
|
104
|
+
|
105
|
+
# Retrieve a valid authorization url from John Deere.
|
106
|
+
url = authorize.authorize_url
|
107
|
+
|
108
|
+
# Queue elevator music while your app serves other users...
|
109
|
+
|
110
|
+
# Re-create the authorize instance in a different process
|
111
|
+
authorize = JD::Authorize.new(API_KEY, API_SECRET, environment: :sandbox)
|
112
|
+
|
113
|
+
# Proceed as normal
|
114
|
+
authorize.verify(code)
|
115
|
+
```
|
116
|
+
|
117
|
+
In a web app, you're prefer that your user doesn't have to copy/paste verification codes. So you can pass in an :oauth_callback url.
|
118
|
+
When the user authorizes your app with John Deere, they are redirected to the url you provide, with the paraameter 'oauth_verifier'
|
119
|
+
that contains the verification code so the user doesn't have to provide it.
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
# Create an authorize object, using your app's API key and secret.
|
123
|
+
authorize = JD::Authorize.new(
|
124
|
+
API_KEY,
|
125
|
+
API_SECRET,
|
126
|
+
environment: :sandbox,
|
127
|
+
oauth_callback: 'https://example.com'
|
128
|
+
)
|
129
|
+
|
130
|
+
# Retrieve a valid authorization url from John Deere.
|
131
|
+
# This will contain the callback url encoded into the
|
132
|
+
# query string for you.
|
133
|
+
url = authorize.authorize_url
|
134
|
+
|
135
|
+
# Queue elevator music while your app serves other users...
|
136
|
+
|
137
|
+
# Re-create the authorize instance in a different process.
|
138
|
+
# It's not necessary to re-initialize with the callback url.
|
139
|
+
authorize = JD::Authorize.new(API_KEY, API_SECRET, environment: :sandbox)
|
140
|
+
|
141
|
+
# Inside a Rails controller, you might do this:
|
142
|
+
authorize.verify(params[:oauth_verifier])
|
143
|
+
```
|
144
|
+
|
145
|
+
## Interacting with the User's John Deere Account
|
146
|
+
|
147
|
+
After authorization is complete, the `Client` object will provide most of the interface for this library. A client can
|
148
|
+
be used with or without user credentials, because some API calls are specific to your application's relationship
|
149
|
+
with John Deere, not your user's. But most interactions will involve user data. Here's how to instantiate a client:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
client = JD::Client.new(
|
153
|
+
# the application's API key
|
154
|
+
API_KEY,
|
155
|
+
|
156
|
+
# the application's API secret
|
157
|
+
API_SECRET,
|
158
|
+
|
159
|
+
# the chosen environment (:sandbox or :live)
|
160
|
+
environment: :sandbox,
|
161
|
+
|
162
|
+
# optional contribution_definition_id. This is needed for some requests,
|
163
|
+
# but the client can be created without it, in order to find it.
|
164
|
+
contribution_definition_id: CONTRIBUTION_DEFINITION_ID,
|
165
|
+
|
166
|
+
# the user's access credentials
|
167
|
+
access: [ACCESS_TOKEN, ACCESS_SECRET]
|
168
|
+
)
|
169
|
+
```
|
170
|
+
|
171
|
+
|
172
|
+
## Using the Client to Do Stuff
|
173
|
+
|
174
|
+
Once you're connected, the client works like a simplified version of ActiveRecord. JSON hashes from the API are
|
175
|
+
converted into objects to be easier to work with. Collections of things, like organizations, handle pagination
|
176
|
+
for you. Just iterate using `each`, `map`, etc, and new pages are fetched as needed.
|
177
|
+
|
178
|
+
This client is a work in progress. You can currently do the following things without resorting to API calls:
|
179
|
+
|
180
|
+
```
|
181
|
+
client
|
182
|
+
├── contribution_products
|
183
|
+
| ├── count
|
184
|
+
| ├── all
|
185
|
+
| ├── first
|
186
|
+
| └── find(contribution_product_id)
|
187
|
+
| └── contribution_definitions
|
188
|
+
| ├── count
|
189
|
+
| ├── all
|
190
|
+
| ├── first
|
191
|
+
| └── find(contribution_definition_id)
|
192
|
+
└── organizations
|
193
|
+
├── count
|
194
|
+
├── all
|
195
|
+
├── first
|
196
|
+
└── find(organization_id)
|
197
|
+
├── assets(attributes)
|
198
|
+
| ├── create(attributes)
|
199
|
+
| ├── count
|
200
|
+
| ├── all
|
201
|
+
| ├── first
|
202
|
+
| └── find(asset_id)
|
203
|
+
| ├── save
|
204
|
+
| ├── update(attributes)
|
205
|
+
| └── locations
|
206
|
+
| ├── create(attributes)
|
207
|
+
| ├── count
|
208
|
+
| ├── all
|
209
|
+
| └── first
|
210
|
+
└── fields
|
211
|
+
├── count
|
212
|
+
├── all
|
213
|
+
├── first
|
214
|
+
└── find(field_id)
|
215
|
+
└── flags
|
216
|
+
├── count
|
217
|
+
├── all
|
218
|
+
└── first
|
219
|
+
```
|
220
|
+
|
221
|
+
|
222
|
+
### [Contribution Products](https://developer.deere.com/#!documentation&doc=.%2Fmyjohndeere%2Fproducts.htm)
|
223
|
+
|
224
|
+
Contribution Product collections act like a list. In addition to all the methods included via Ruby's
|
225
|
+
[Enumerable Module](https://ruby-doc.org/core-2.7.0/Enumerable.html), contribution product
|
226
|
+
collections support the following methods:
|
227
|
+
|
228
|
+
* all
|
229
|
+
* count
|
230
|
+
* first
|
231
|
+
* find(contribution\_product\_id)
|
232
|
+
|
233
|
+
An individual contribution product supports the following methods and associations:
|
234
|
+
|
235
|
+
* id
|
236
|
+
* market_place_name
|
237
|
+
* market_place_description
|
238
|
+
* default\_locale
|
239
|
+
* current\_status
|
240
|
+
* activation\_callback
|
241
|
+
* preview\_images
|
242
|
+
* supported\_regions
|
243
|
+
* supported\_operation\_centers
|
244
|
+
* links
|
245
|
+
* contribution\_definitions (collection of this contribution product's contribution definitions)
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
client.contribution_products
|
249
|
+
# => collection of contribution products under this client
|
250
|
+
|
251
|
+
client.contribution_products.count
|
252
|
+
# => 1
|
253
|
+
|
254
|
+
client.contribution_products.first
|
255
|
+
# => an individual contribution product
|
256
|
+
|
257
|
+
contribution_product = client.contribution_products.find(1234)
|
258
|
+
# => an individual contribution product, fetched by ID
|
259
|
+
|
260
|
+
contribution_product.market_place_name
|
261
|
+
# => 'Market Place Name'
|
262
|
+
|
263
|
+
contribution_product.contribution_definitions
|
264
|
+
# => collection of contribution definitions belonging to this contribution product
|
265
|
+
```
|
266
|
+
|
267
|
+
|
268
|
+
### [Contribution Definitions](https://developer.deere.com/#!documentation&doc=.%2Fmyjohndeere%2Fproducts.htm)
|
269
|
+
|
270
|
+
Handles a contribution product's contribution definitions. Contribution definition collections support the following methods:
|
271
|
+
|
272
|
+
* all
|
273
|
+
* count
|
274
|
+
* first
|
275
|
+
* find(contribution\_definition\_id)
|
276
|
+
|
277
|
+
An individual contribution definition supports the following methods and associations:
|
278
|
+
|
279
|
+
* id
|
280
|
+
* name
|
281
|
+
* links
|
282
|
+
|
283
|
+
```ruby
|
284
|
+
contribution_product.contribution_definitions
|
285
|
+
# => collection of contribution definitions under this contribution product
|
286
|
+
|
287
|
+
client.contribution_definitions.count
|
288
|
+
# => 1
|
289
|
+
|
290
|
+
client.contribution_definitions.first
|
291
|
+
# => an individual contribution definition
|
292
|
+
|
293
|
+
contribution_definition = contribution_product.contribution_definitions.find(1234)
|
294
|
+
# => an individual contribution definition, fetched by ID
|
295
|
+
|
296
|
+
contribution_definition.name
|
297
|
+
# => 'Contribution Definition Name'
|
298
|
+
```
|
299
|
+
|
300
|
+
|
301
|
+
### [Organizations](https://developer.deere.com/#!documentation&doc=myjohndeere%2Forganizations.htm)
|
302
|
+
|
303
|
+
Handles an account's organizations. Organization collections support the following methods:
|
304
|
+
|
305
|
+
* all
|
306
|
+
* count
|
307
|
+
* first
|
308
|
+
* find(organization\_id)
|
309
|
+
|
310
|
+
An individual organization supports the following methods and associations:
|
311
|
+
|
312
|
+
* id
|
313
|
+
* name
|
314
|
+
* type
|
315
|
+
* member?
|
316
|
+
* links
|
317
|
+
* assets (collection of this organization's assets)
|
318
|
+
* fields (collection of this organization's fields)
|
319
|
+
|
320
|
+
The `count` method only requires loading the first page of results, so it's a relatively cheap call. On the other hand,
|
321
|
+
`all` forces the entire collection to be loaded from John Deere's API, so use with caution. Organizations cannot be
|
322
|
+
created via the API, so there is no `create` method on this collection.
|
323
|
+
|
324
|
+
```ruby
|
325
|
+
client.organizations
|
326
|
+
# => collection of organizations under this client
|
327
|
+
|
328
|
+
client.organizations.count
|
329
|
+
# => 15
|
330
|
+
|
331
|
+
client.organizations.first
|
332
|
+
# => an individual organization object
|
333
|
+
|
334
|
+
organization = client.organizations.find(1234)
|
335
|
+
# => an individual organization object, fetched by ID
|
336
|
+
|
337
|
+
organization.name
|
338
|
+
# => 'Smith Farms'
|
339
|
+
|
340
|
+
organization.type
|
341
|
+
# => 'customer'
|
342
|
+
|
343
|
+
organization.member?
|
344
|
+
# => true
|
345
|
+
|
346
|
+
organization.links
|
347
|
+
# => {
|
348
|
+
# 'self' => 'https://sandboxapi.deere.com/platform/organizations/1234',
|
349
|
+
# 'machines' => 'https://sandboxapi.deere.com/platform/organizations/1234/machines',
|
350
|
+
# 'wdtCapableMachines' => 'https://sandboxapi.deere.com/platform/organizations/1234/machines?capability=wdt'
|
351
|
+
# }
|
352
|
+
|
353
|
+
organization.assets
|
354
|
+
# => collection of assets belonging to this organization
|
355
|
+
|
356
|
+
organization.fields
|
357
|
+
# => collection of fields belonging to this organization
|
358
|
+
```
|
359
|
+
|
360
|
+
|
361
|
+
### [Assets](https://developer.deere.com/#!documentation&doc=.%2Fmyjohndeere%2Fassets.htm)
|
362
|
+
|
363
|
+
Handles an organization's assets. Asset collections support the following methods:
|
364
|
+
|
365
|
+
* create(attributes)
|
366
|
+
* all
|
367
|
+
* count
|
368
|
+
* first
|
369
|
+
* find(asset\_id)
|
370
|
+
|
371
|
+
An individual asset supports the following methods and associations:
|
372
|
+
|
373
|
+
* id
|
374
|
+
* title
|
375
|
+
* category
|
376
|
+
* type
|
377
|
+
* sub\_type
|
378
|
+
* links
|
379
|
+
* update(attributes)
|
380
|
+
* locations (collection of this asset's locations)
|
381
|
+
|
382
|
+
```ruby
|
383
|
+
organization = client.organizations.first
|
384
|
+
# => the first organization returned by the client
|
385
|
+
|
386
|
+
organization.assets
|
387
|
+
# => collection of assets belonging to this organization
|
388
|
+
|
389
|
+
asset = organization.assets.find(123)
|
390
|
+
# => an individual asset object, fetched by ID
|
391
|
+
|
392
|
+
asset.title
|
393
|
+
# => 'AgThing Water Device'
|
394
|
+
|
395
|
+
asset.category
|
396
|
+
# => 'DEVICE'
|
397
|
+
|
398
|
+
asset.type
|
399
|
+
# => 'SENSOR'
|
400
|
+
|
401
|
+
asset.sub_type
|
402
|
+
# => 'OTHER'
|
403
|
+
|
404
|
+
asset.links
|
405
|
+
# => a hash of API urls related to this asset
|
406
|
+
```
|
407
|
+
|
408
|
+
The `create` method creates the asset in the John Deere platform, and returns the newly created record.
|
409
|
+
|
410
|
+
```ruby
|
411
|
+
asset = organization.assets.create(
|
412
|
+
title: 'Asset Title',
|
413
|
+
asset_category: 'DEVICE',
|
414
|
+
asset_type: 'SENSOR',
|
415
|
+
asset_sub_type: 'ENVIRONMENTAL'
|
416
|
+
)
|
417
|
+
|
418
|
+
asset.title
|
419
|
+
# => 'Asset Title'
|
420
|
+
```
|
421
|
+
|
422
|
+
The `update` method updates the local object, and also the asset on the John Deere platform.
|
423
|
+
Only the title of an asset can be updated.
|
424
|
+
|
425
|
+
```ruby
|
426
|
+
asset.update(title: 'New Title')
|
427
|
+
asset.title
|
428
|
+
# => 'New Title', also John Deere record is updated
|
429
|
+
```
|
430
|
+
|
431
|
+
The `save` method updates John Deere with any local changes that have been made.
|
432
|
+
|
433
|
+
```ruby
|
434
|
+
asset.title = 'New Title'
|
435
|
+
asset.save
|
436
|
+
# => Successful Net::HTTPNoContent object
|
437
|
+
```
|
438
|
+
|
439
|
+
|
440
|
+
### [Asset Locations](https://developer.deere.com/#!documentation&doc=.%2Fmyjohndeere%2Fassets.htm)
|
441
|
+
|
442
|
+
Handles an asset's locations. Asset Location collections support the following methods:
|
443
|
+
|
444
|
+
* create(attributes)
|
445
|
+
* all
|
446
|
+
* count
|
447
|
+
* first
|
448
|
+
|
449
|
+
An individual location supports the following methods:
|
450
|
+
|
451
|
+
* timestamp
|
452
|
+
* geometry
|
453
|
+
* measurement\_data
|
454
|
+
|
455
|
+
```ruby
|
456
|
+
asset = organizations.assets.first
|
457
|
+
# => the first asset returned by the organization
|
458
|
+
|
459
|
+
asset.locations
|
460
|
+
# => collection of locations belonging to this asset
|
461
|
+
|
462
|
+
location = asset.locations.first
|
463
|
+
# => the first location returned by the asset. Note that locations do not have their own id's
|
464
|
+
# in the JD platform, and therefore cannot be requested individually via a "find" method.
|
465
|
+
|
466
|
+
location.timestamp
|
467
|
+
# => "2019-11-11T23:00:00.000Z"
|
468
|
+
# John Deere includes 3 decimal places in the format, but does not actually
|
469
|
+
# store fractions of a second, so it will always end in ".000". This is
|
470
|
+
# important, because timestamps must be unique.
|
471
|
+
|
472
|
+
location.geometry
|
473
|
+
# => a GeoJSON formatted hash, for example:
|
474
|
+
# {
|
475
|
+
# "type"=>"Feature",
|
476
|
+
# "geometry"=>{
|
477
|
+
# "geometries"=>[
|
478
|
+
# {
|
479
|
+
# "coordinates"=>[-95.123456, 40.123456],
|
480
|
+
# "type"=>"Point"
|
481
|
+
# }
|
482
|
+
# ],
|
483
|
+
# "type"=>"GeometryCollection"
|
484
|
+
# }
|
485
|
+
# }
|
486
|
+
|
487
|
+
location.measurement_data
|
488
|
+
# => the status details of this location, for example:
|
489
|
+
# [
|
490
|
+
# {
|
491
|
+
# "@type"=>"BasicMeasurement",
|
492
|
+
# "name"=>"[Soil Temperature](http://example.com/current_temperature)",
|
493
|
+
# "value"=>"21.0",
|
494
|
+
# "unit"=>"°C"
|
495
|
+
# }
|
496
|
+
# ]
|
497
|
+
```
|
498
|
+
|
499
|
+
The `create` method creates the location in the John Deere platform, and returns the newly created
|
500
|
+
object from John Deere. However, there will be no new information since there is no unique ID
|
501
|
+
generated. The timestamp submitted (which defaults to "now") will be rounded
|
502
|
+
to the nearest second.
|
503
|
+
|
504
|
+
```ruby
|
505
|
+
locaton = asset.locatons.create(
|
506
|
+
# You can pass fractional seconds, but they will be truncated by JD.
|
507
|
+
timestamp: "2019-11-11T23:00:00.123Z",
|
508
|
+
|
509
|
+
# JD requires more complicated JSON geometry, but this client will convert a simple
|
510
|
+
# set of lat/long coordinates into the larger format automatically.
|
511
|
+
geometry: [-95.123456, 40.123456],
|
512
|
+
|
513
|
+
# This is a list of "measurements"
|
514
|
+
measurement_data: [
|
515
|
+
{
|
516
|
+
name: 'Temperature',
|
517
|
+
value: '68.0',
|
518
|
+
unit: 'F'
|
519
|
+
}
|
520
|
+
]
|
521
|
+
)
|
522
|
+
|
523
|
+
location.timestamp
|
524
|
+
# => "2019-11-11T23:00:00.000Z"
|
525
|
+
# Note that the timestamp's fractional second is truncated by John Deere, though they
|
526
|
+
# still return the record with three digits of precision.
|
527
|
+
|
528
|
+
location.geometry
|
529
|
+
# => a GeoJSON formatted hash in its larger format
|
530
|
+
# {
|
531
|
+
# "type"=>"Feature",
|
532
|
+
# "geometry"=>{
|
533
|
+
# "geometries"=>[
|
534
|
+
# {
|
535
|
+
# "coordinates"=>[-95.123456, 40.123456],
|
536
|
+
# "type"=>"Point"
|
537
|
+
# }
|
538
|
+
# ],
|
539
|
+
# "type"=>"GeometryCollection"
|
540
|
+
# }
|
541
|
+
# }
|
542
|
+
|
543
|
+
location.measurement_data
|
544
|
+
# [
|
545
|
+
# {
|
546
|
+
# "@type"=>"BasicMeasurement",
|
547
|
+
# "name"=>"Temperature",
|
548
|
+
# "value"=>"68.0",
|
549
|
+
# "unit"=>"F"
|
550
|
+
# }
|
551
|
+
# ]
|
552
|
+
|
553
|
+
```
|
554
|
+
|
555
|
+
There is no updating or deleting of a location. The newest location record always acts as the status
|
556
|
+
for the given asset, and is what appears on the map view.
|
557
|
+
|
558
|
+
Note that locations are called "Asset Locations" in John Deere, but we call the association "locations", as in
|
559
|
+
`asset.locations`, for brevity.
|
560
|
+
|
561
|
+
|
562
|
+
### [Fields](https://developer.deere.com/#!documentation&doc=myjohndeere%2FfieldsADS.htm)
|
563
|
+
|
564
|
+
Handles an organization's fields. Field collections support the following methods:
|
565
|
+
|
566
|
+
* all
|
567
|
+
* count
|
568
|
+
* first
|
569
|
+
* find(field\_id)
|
570
|
+
|
571
|
+
An individual field supports the following methods and associations:
|
572
|
+
|
573
|
+
* id
|
574
|
+
* name
|
575
|
+
* archived?
|
576
|
+
* links
|
577
|
+
* flags (collection of this field's flags)
|
578
|
+
|
579
|
+
The `count` method only requires loading the first page of results, so it's a relatively cheap call. On the other hand,
|
580
|
+
`all` forces the entire collection to be loaded from John Deere's API, so use with caution. Fields can be
|
581
|
+
created via the API, but there is no `create` method on this collection yet.
|
582
|
+
|
583
|
+
```ruby
|
584
|
+
organization.fields
|
585
|
+
# => collection of fields under this organization
|
586
|
+
|
587
|
+
organization.fields.count
|
588
|
+
# => 15
|
589
|
+
|
590
|
+
organization.fields.first
|
591
|
+
# => an individual field object
|
592
|
+
|
593
|
+
field = organization.fields.find(1234)
|
594
|
+
# => an individual field object, fetched by ID
|
595
|
+
|
596
|
+
field.name
|
597
|
+
# => 'Smith Field'
|
598
|
+
|
599
|
+
field.archived?
|
600
|
+
# => false
|
601
|
+
|
602
|
+
field.links
|
603
|
+
# => a hash of API urls related to this field
|
604
|
+
|
605
|
+
field.flags
|
606
|
+
# => collection of flags belonging to this field
|
607
|
+
```
|
608
|
+
|
609
|
+
|
610
|
+
### [Flags](https://developer.deere.com/#!documentation&doc=.%2Fmyjohndeere%2Fflags.htm)
|
611
|
+
|
612
|
+
Handles a field's flags. Flag collections support the following methods. Note, John Deere does not provide an endpoint to retrieve a specific flag by id:
|
613
|
+
|
614
|
+
* all
|
615
|
+
* count
|
616
|
+
* first
|
617
|
+
|
618
|
+
An individual flag supports the following methods and associations:
|
619
|
+
|
620
|
+
* id
|
621
|
+
* notes
|
622
|
+
* geometry
|
623
|
+
* archived?
|
624
|
+
* proximity\_alert\_enabled?
|
625
|
+
* links
|
626
|
+
|
627
|
+
The `count` method only requires loading the first page of results, so it's a relatively cheap call. On the other hand,
|
628
|
+
`all` forces the entire collection to be loaded from John Deere's API, so use with caution. Flags can be
|
629
|
+
created via the API, but there is no `create` method on this collection yet.
|
630
|
+
|
631
|
+
```ruby
|
632
|
+
field.flags
|
633
|
+
# => collection of flags under this field
|
634
|
+
|
635
|
+
field.flags.count
|
636
|
+
# => 15
|
637
|
+
|
638
|
+
flag = field.flags.first
|
639
|
+
# => an individual flag object
|
640
|
+
|
641
|
+
flag.notes
|
642
|
+
# => 'A big rock on the left after entering the field'
|
643
|
+
|
644
|
+
flag.geometry
|
645
|
+
# => a GeoJSON formatted hash, for example:
|
646
|
+
# {
|
647
|
+
# "type"=>"Feature",
|
648
|
+
# "geometry"=>{
|
649
|
+
# "geometries"=>[
|
650
|
+
# {
|
651
|
+
# "coordinates"=>[-95.123456, 40.123456],
|
652
|
+
# "type"=>"Point"
|
653
|
+
# }
|
654
|
+
# ],
|
655
|
+
# "type"=>"GeometryCollection"
|
656
|
+
# }
|
657
|
+
# }
|
658
|
+
|
659
|
+
|
660
|
+
field.archived?
|
661
|
+
# => false
|
662
|
+
|
663
|
+
field.proximity_alert_enabled?
|
664
|
+
# => true
|
665
|
+
|
666
|
+
field.links
|
667
|
+
# => a hash of API urls related to this flag
|
668
|
+
```
|
669
|
+
|
670
|
+
|
671
|
+
## Direct API Requests
|
672
|
+
|
673
|
+
While the goal of the client is to eliminate the need to make/interpret calls to the John Deere API, it's important
|
674
|
+
to be able to make calls that are not yet fully supported by the client. Or sometimes, you need to troubleshoot.
|
675
|
+
|
676
|
+
|
677
|
+
### GET
|
678
|
+
|
679
|
+
|
680
|
+
GET requests require only a resource path.
|
681
|
+
|
682
|
+
```ruby
|
683
|
+
client.get('/organizations')
|
684
|
+
```
|
685
|
+
|
686
|
+
Abbreviated sample response:
|
687
|
+
|
688
|
+
```json
|
689
|
+
{
|
690
|
+
"links": ["..."],
|
691
|
+
"total": 1,
|
692
|
+
"values": [
|
693
|
+
{
|
694
|
+
"@type": "Organization",
|
695
|
+
"name": "ABC Farms",
|
696
|
+
"type": "customer",
|
697
|
+
"member": true,
|
698
|
+
"id": "123123",
|
699
|
+
"links": ["..."]
|
700
|
+
}
|
701
|
+
]
|
702
|
+
}
|
703
|
+
```
|
704
|
+
|
705
|
+
This won't provide any client goodies like pagination or validation, but it does parse the returned JSON.
|
706
|
+
|
707
|
+
|
708
|
+
### POST
|
709
|
+
|
710
|
+
POST requests require a resource path, and a hash for the request body. The client will camelize the keys, and convert to JSON.
|
711
|
+
|
712
|
+
```ruby
|
713
|
+
client.post(
|
714
|
+
'/organizations/123123/assets',
|
715
|
+
{
|
716
|
+
"title"=>"i like turtles",
|
717
|
+
"assetCategory"=>"DEVICE",
|
718
|
+
"assetType"=>"SENSOR",
|
719
|
+
"assetSubType"=>"ENVIRONMENTAL",
|
720
|
+
"links"=>[
|
721
|
+
{
|
722
|
+
"@type"=>"Link",
|
723
|
+
"rel"=>"contributionDefinition",
|
724
|
+
"uri"=>"https://sandboxapi.deere.com/platform/contributionDefinitions/CONTRIBUTION_DEFINITION_ID"
|
725
|
+
}
|
726
|
+
]
|
727
|
+
}
|
728
|
+
)
|
729
|
+
```
|
730
|
+
|
731
|
+
John Deere's standard response is a 201 HTTP status code, with the message "Created". This method returns the full Net::HTTP response.
|
732
|
+
|
733
|
+
|
734
|
+
### PUT
|
735
|
+
|
736
|
+
PUT requests require a resource path, and a hash for the request body. The client will camelize the keys, and convert to JSON.
|
737
|
+
|
738
|
+
```ruby
|
739
|
+
client.put(
|
740
|
+
'/assets/123123',
|
741
|
+
{
|
742
|
+
"title"=>"i REALLY like turtles",
|
743
|
+
"assetCategory"=>"DEVICE",
|
744
|
+
"assetType"=>"SENSOR",
|
745
|
+
"assetSubType"=>"ENVIRONMENTAL",
|
746
|
+
"links"=>[
|
747
|
+
{
|
748
|
+
"@type"=>"Link",
|
749
|
+
"rel"=>"contributionDefinition",
|
750
|
+
"uri"=>"https://sandboxapi.deere.com/platform/contributionDefinitions/CONTRIBUTION_DEFINITION_ID"
|
751
|
+
}
|
752
|
+
]
|
753
|
+
}
|
754
|
+
)
|
755
|
+
```
|
756
|
+
|
757
|
+
John Deere's standard response is a 204 HTTP status code, with the message "No Content". This method returns the full Net::HTTP response.
|
758
|
+
|
759
|
+
|
760
|
+
### DELETE
|
761
|
+
|
762
|
+
DELETE requests require only a resource path.
|
763
|
+
|
764
|
+
```ruby
|
765
|
+
client.delete('/assets/123123')
|
766
|
+
```
|
767
|
+
|
768
|
+
John Deere's standard response is a 204 HTTP status code, with the message "No Content". This method returns the full Net::HTTP response.
|
769
|
+
|
770
|
+
|
771
|
+
## Errors
|
772
|
+
|
773
|
+
Custom errors help clearly identify problems when using the client:
|
774
|
+
|
775
|
+
* **UnsupportedEnvironmentError** is raised when you attempt to instantiate a client with an
|
776
|
+
unrecognized environment. Valid environments are `:sandbox` or `:production`.
|
777
|
+
* **InvalidRecordError** is raised when bad input has been given, in an attempt to create or update
|
778
|
+
a record on the John Deere platform.
|
779
|
+
* **MissingContributionDefinitionIdError** is raised when the optional contribution\_definition\_id
|
780
|
+
has not been set in the client, but an operation has been attempted that requires it - like
|
781
|
+
creating an asset in the John Deere platform.
|
782
|
+
* **TypeMismatchError** is raised when a model is instantiated, typically when a record is received
|
783
|
+
from John Deere and is being converted into a Ruby object. Model instantiation is normally handled
|
784
|
+
by request objects, but this error is helpful if you're instantiating your own models for advanced
|
785
|
+
usage.
|
786
|
+
* **NotYetImplementedError** is raised when you attempt to use a feature that is earmarked for future
|
787
|
+
development, but hasn't been implemented in this client yet. These are a great chance to contribute
|
788
|
+
to this gem!
|
789
|
+
|
790
|
+
|
791
|
+
## How Can I Help?
|
792
|
+
|
793
|
+
### Give Us a Star!
|
794
|
+
|
795
|
+
*Star* this gem on [GitHub](https://github.com/Intellifarm/my_john_deere_api). It helps developers
|
796
|
+
find and choose this gem over others that may be out there. To our knowledge, there are no other
|
797
|
+
John Deere gems that are being actively maintained.
|
798
|
+
|
799
|
+
|
800
|
+
### Contribute to This Gem
|
801
|
+
|
802
|
+
The easiest way to contribute is:
|
803
|
+
|
804
|
+
* Clone the repo
|
805
|
+
* Create a feature branch
|
806
|
+
* Grep for "raise NotYetImplementedError" in the lib directory
|
807
|
+
* Replace one of these exceptions with working code, following the conventions used in the rest of the app
|
808
|
+
* TEST EVERYTHING!
|
809
|
+
* Run tests.
|
810
|
+
* You may need to regenerate all VCR cassettes from scratch.
|
811
|
+
* All VCR cassettes should be pre-recorded in `vcr_setup`
|
812
|
+
* Anything that is created in the JD sandbox as a result of running the tests should be removed, also in `vcr_setup`.
|
813
|
+
* When tests are passing, submit a Pull Request.
|