API Changes

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 (was Content-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.
  • 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 into quantity entities)
  • log_category -> category
  • log_owner -> owner
  • material (migrated to "Material" quantity entities)
  • seed_source -> source
  • soil_lab -> lab
  • water_lab -> lab
  • 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.

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 and archived (see "Asset status" below)
  • crop -> plant_type
  • date -> birthdate (on animal 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 (either active or archived).
  • 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 the intrinsic_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