API Changes
3.x vs 2.x
The Simple OAuth module has been updated to version 6. This includes a few breaking changes which may affect API integrations. farmOS includes code to handle the transition of its own OAuth clients and scopes, but if you have made any additional clients that used special roles they will also need to be updated.
The biggest changes are that the "Implicit" grant type has been removed, and the "Password Credentials" grant type has been moved to an optional "Simple OAuth Password Grant" module, which must be enabled in order to use that grant type.
There have also been changes to how scopes are provided. User roles no longer
act as scopes by default. Instead, scopes must be created separately to
reference each role they represent. Scopes can also be associated with
individual permissions and can reference parent scopes to create
hierarchical scope trees. farmOS provides static
scopes for each of the
default roles: farm_manager
, farm_worker
and farm_viewer
.
The default farmOS client that is included with farmOS has also been moved to a separate module that is not enabled by default. After the update to farmOS 3.x, all access tokens will be invalidated, but refresh tokens will still work to get a new access token.
Other notable changes:
- Material quantities can reference multiple material types
- Log
timestamp
is marked asrequired
in JSON Schema - Allowed values are declared in JSON Schema
oneOf
/anyOf
enumerations for more entity attributes.
2.x vs 1.x
farmOS 1.x used the RESTful Web Services module, which provided API endpoints for each entity type (asset, log, taxonomy term, etc).
farmOS 2.x uses the new JSON:API module included with Drupal core, which follows the JSON:API specification for defining API resources.
The root API endpoint is /api
.
JSON Schema
farmOS 2.x also provides JSON Schema information
about all available resources. The root endpoint for schema information is
/api/schema
.
In farmOS 1.x, the /farm.json
endpoint provided similar information in the
resources
property. This has been removed in favor of JSON Schema.
Authentication
See API Authentication for more information about authorizing and authenticating farmOS 2.x API requests.
Notable changes from 1.x include:
- The new authorization URL is
/oauth/authorize
(was/oauth2/authorize
). - The new token URL is
/oauth/token
(was/oauth2/token
). - Requests should use
Content-Type: application/vnd.api+json
(wasContent-Type: application/json
).
Farm info endpoint
In farmOS 1.x, an informational API endpoint was provided at /farm.json
. This
included various information describing the farmOS server configuration,
authenticated user, installed languages and available entity types and bundles.
This information was provided as either a simple value or a JSON object:
{
"name": "My Farm",
"url": "https://myfarm.mydomain.com",
"api_version": "1.0",
"system_of_measurement": "metric",
"user": { ... },
"languages": { ... },
"resources": { ... },
"metrics": { ... }
}
In farmOS 2.x, a root /api
endpoint either provides this information, or is a
gateway to this information.
The simple values previously available from
/farm.json
are now provided in the meta.farm
object at /api
:
{
"jsonapi":{ ... },
"data":[],
"meta":{
"links":{
"me":{
"meta":{
"id":"7b2af019-3191-40ca-b221-616f9a365722"
},
"href":"http://localhost/api/user/user/7b2af019-3191-40ca-b221-616f9a365722"
}
},
"farm":{
"name":"My farm name",
"url":"http://localhost",
"version":"2.x",
"system_of_measurement": "metric"
}
},
"links":{ ... }
}
The resources
object has been replaced with the links
object that
describes all the available resource types and their endpoints. Information
previously provided in the other JSON objects are now available as standalone
resources at their respective endpoints:
user
-/api/user/user
- The authenticated user's ID is included in the
meta.links.me
object with a link to the user's resource. The user's attributes, such as name and language, can be retrieved from that endpoint.
- The authenticated user's ID is included in the
languages
-/api/configurable_language/configurable_language
Resource endpoints
In farmOS 1.x, API endpoints for each entity type were available at
/[entity_type].json
.
For example: /log.json
In farmOS 2.x, a root /api
endpoint is provided, with a links
object that
describes all the available resource types and their endpoints. These follow
a URL pattern of /api/[entity-type]/[bundle]
.
For example: /api/log/activity
"Bundles" are "sub-types" that can have different sets (bundles) of fields on them. For example, a "Seeding Log" and a "Harvest Log" will collect different information, but both are "Logs" (events).
To illustrate the difference between 1.x and 2.x, here are the endpoints for retrieving all Activity logs.
- farmOS 1.x:
/log.json?type=farm_activity
- farmOS 2.x:
/api/log/activity
IDs
farmOS 2.x assigns UUIDs (universally unique identifiers) to all resources, and uses them in the API.
This differs from farmOS 1.x, which used the integer IDs directly from the auto-incrementing database table that the record was pulled from. The benefit of UUIDs is they are guaranteed to be unique across multiple farmOS databases, whereas the old IDs were not.
The internal integer IDs are not exposed via the API, so all code that needs to integrate should use the new UUIDs instead.
Also note that the migration from farmOS 1.x to 2.x does not preserve the internal integer IDs, so they may be different after migrating to 2.x.
Record structure
JSON:API has some rules about how records are structured that differ from farmOS 1.x. These rules make the API more explicit.
In farmOS 1.x, all the fields/properties of a record were on the same level.
For example, a simple observation log looked like this:
{
"id": "5"
"type": "farm_observation",
"name": "Test observation",
"timestamp": "1526584271",
"asset": [
{
"resource": "farm_asset",
"id": "123"
}
]
}
In farmOS 2.x, JSON:API dictates that the "attributes" and "relationships" of a
record be explicitly declared under attributes
and relationships
properties
in the JSON.
The same record in farmOS 2.x looks like:
{
"id": "9bc49ffd-76e8-4f86-b811-b721cb771327"
"type": "log--observation",
"attributes": {
"name": "Test observation",
"timestamp": "1526584271",
},
"relationships": {
"asset": {
"data": [
{
"type": "asset--animal",
"id": "75116e3e-c45e-431d-8b58-1fce6bb315cf",
}
]
}
}
}
Filtering
The URL query parameters for filtering results have a different syntax in 2.x. Refer to the Drupal.org JSON:API Filtering documentation for more information.
To illustrate, this is how to filter activity logs by their completed status:
- farmOS 1.x:
/log.json?type=activity&done=1
- farmOS 2.x:
/api/log/activity?filter[status]=complete
Text format
Long text fields (like notes
) include value
and format
sub-properties,
where value
is the text value, and format
is the "Text format" to use when
displaying the text. This is used to filter user-supplied text, to only allow
certain HTML tags (filtering out potential XSS vulnerabilities), convert URLs
to links, etc.
This works the same in farmOS 2.x, but the default format
has changed from
farm_format
to default
.
Logs
Log types
The farm_
prefix has been dropped from all log type names. For example, in
farmOS 1.x an Activity log was farm_activity
, and in farmOS 2.x it is simply
activity
.
Additionally, the "Soil test" and "Water test" log types have been merged into a single "Lab test" log type.
Also note that "Sale" and "Purchase" logs have been moved out of farmOS core to a new farmOS Ledger module.
Below is the full list of log types in farmOS 1.x and their new names in 2.x:
farm_activity
->activity
farm_harvest
->harvest
farm_input
->input
farm_maintenance
->maintenance
farm_medical
->medical
farm_observation
->observation
farm_seeding
->seeding
farm_soil_test
->lab_test
farm_transplanting
->transplanting
farm_water_test
->lab_test
Log fields
Log field names are largely unchanged, with a few exceptions (note that new fields are not listed here):
area
->location
(See "Areas" below)date_purchase
->purchase_date
done
->status
(see "Log status" below)files
->file
flags
->flag
geofield
->geometry
images
->image
input_method
->method
input_source
->source
inventory
(merged intoquantity
entities)log_category
->category
log_owner
->owner
material
(migrated to "Material"quantity
entities)seed_source
->source
soil_lab
->lab
(see "Laboratory" below)water_lab
->lab
(see "Laboratory" below)quantity
(see "Quantities" below)
See also "Text format" above for information about the changes to the format
parameter of long text fields.
Log status
In farmOS 1.x, logs had a boolean property called done
which was either 1
(done) or 0
(not done).
In 2.x, the done
property has changed to status
, and can be set to either
done
or pending
. Additional states may be added in the future.
Laboratory
In farmOS 1.x, Soil test and Water test logs had a "Laboratory" field for storing the name of the lab that performed the test as a string.
In 2.x, a new "Labs" taxonomy has been added, and the "Laboratory" field on Lab test logs is a term reference field.
Assets
Asset records in farmOS 1.x had an entity type of farm_asset
. In farmOS 2.x,
the farm_
prefix has been dropped. The entity type is now simply asset
.
Asset types
Asset type names are largely unchanged, with one notable exception: the "Planting" asset type has been renamed to "Plant".
Below is the full list of asset types in farmOS 1.x and their new names in 2.x:
animal
(unchanged)compost
(unchanged)equipment
(unchanged)group
(unchanged)planting
->plant
sensor
(unchanged)
Asset fields
Asset field names are largely unchanged, with a few exceptions (note that new fields are not listed here):
animal_castrated
->is_castrated
animal_nicknames
->nickname
animal_sex
->sex
animal_tag
->id_tag
archived
->status
andarchived
(see "Asset status" below)crop
->plant_type
date
->birthdate
(onanimal
assets)description
->notes
(see also "Text format" above)flags
->flag
files
->file
images
->image
Asset status
In farmOS 1.x, assets had a property called archived
which was either 0
,
which indicated that the asset was active, or a timestamp that recorded when
the asset was archived.
In farmOS 2.x, these have been split into two separate fields:
status
- The status of the asset (eitheractive
orarchived
).archived
- The timestamp when the asset was archived. This will be empty if the asset is active.
Taxonomies
farmOS 2.x continues to use Drupal's core taxonomy_term
entities to represent
vocabularies of terms. The vocabulary machine names have changed, to drop the
farm_
prefix, and to standardize plurality.
farm_animal_types
->animal_type
farm_areas
has been removed (see "Areas" below)farm_log_categories
->log_category
farm_materials
->material_type
farm_season
->season
farm_crops
->plant_type
farm_crop_families
->crop_family
farm_quantity_units
->unit
Areas
farmOS 1.x had the concept of "Areas" for representing places/locations. These
were taxonomy terms in the farm_areas
vocabulary. In farmOS 2.x, these areas
are migrated to new asset types, and any asset can now be designated as a
"location". New asset types are provided, including "Land", "Structure", and
"Water", which have the "location" designation by default. Additional types can
be provided by modules.
Because any asset can be a location, some new fields are available on assets, including:
is_location
- Boolean indicating whether or not other assets can be moved to this asset.is_fixed
- Boolean indicating that the asset has a fixed geometry and therefore does not move.intrinsic_geometry
- A geofield representing the intrinsic geometry of "fixed" assets.
Additionally, two "computed" fields are available on all assets, which provide quick access to the asset's current location and geometry, regardless of whether or not it is "fixed":
geometry
- The asset's current geometry. This will be the same as theintrinsic_geometry
for "fixed" assets. Otherwise, it will mirror the geometry of the asset's most recent movement log.location
- The asset's current location (an asset reference). This will always be empty for "fixed" assets. Otherwise, it will mirror the location reference field of the asset's most recent movement log.
Quantities
In farmOS 1.x, log quantities were saved within separate Field Collection entities. farmOS used the RESTful Web Services Field Collection module to hide the fact that these were separate entities, allowing their field to be accessed and modified in the same request to the host entity.
In farmOS 2.x, quantities are represented as quantity
entities. These are
referenced under a log's relationships
in JSON:API, and have a JSON:API
resource name of quantity--quantity
. In order to add a quantity to a new or
existing log, they must be created in a separate API request before they can be
referenced by the log. Quantities still have measure
, value
, unit
and
label
fields.
Files
farmOS 1.x used the RESTful Web Services File module to enable file uploads via the API. The API accepted an array of base64-encoded strings to be included in the JSON body payload of the host entity.
In farmOS 2.x, file uploads are supported by the core JSON:API module. Instead
of base64-encoded strings, the API requires a separate POST
of binary data
for each file to upload. This reflects "real" PHP upload semantics, allowing
for faster and larger file uploads via the API. This also means that files
cannot be uploaded in the same request that creates an entity. Instead, a file
can be uploaded to an existing entity in a single request, or the file can be
uploaded and assigned to an entity in two separate requests. Refer to the
Drupal.org JSON:API File Uploads documentation
for more information.
For example, to upload an image file to an existing observation log with curl
:
curl https://example.com/api/log/observation/{UUID}/image \
-H 'Accept: application/vnd.api+json' \
-H 'Content-Type: application/octet-stream' \
-H 'Content-Disposition: attachment; filename="observation.jpg"' \
-H 'Authorization: Bearer …………' \
--data-binary @/path/to/observation.jpg