clean install

This commit is contained in:
2024-12-10 15:08:16 +01:00
commit e14eb2d8fd
31193 changed files with 3555714 additions and 0 deletions

View File

@@ -0,0 +1,172 @@
# Authentication
farmOS includes an OAuth2 Authorization server for providing 1st and 3rd party
clients access to the farmOS API. Rather than using a user's username and
password to both *authorize and authenticate* a request, OAuth2 requires
users to complete an *authorization flow* that generates an `access_token`
to be used for authentication. Access tokens are provided to both 1st and
3rd party clients who wish to access the server's protected resources. Clients
store the `access token` instead of the user's credentials, which makes it a
more secure authentication method.
Read more about the [OAuth 2.0 standards](https://oauth.net/2/).
## Client Libraries
The [farmOS.py](https://github.com/farmOS/farmOS.py) and
[farmOS.js](https://github.com/farmOS/farmOS.js) client libraries use the
OAuth2 protocol to interact with the farmOS API.
## OAuth2 Bearer Tokens
Once you have an OAuth2 token, you can authenticate requests to the farmOS
server by including an `Authentication: Bearer {access_token}` header.
## OAuth2 Details
The OAuth protocol defines a process where users *authorize* 1st and 3rd
party *clients* with *scoped* access to data on the server. The following
describes the details necessary for using OAuth2 authorization with a farmOS
server.
### Scopes
OAuth Scopes define different levels of access. The farmOS server
implements scopes that represent individual roles or permissions. Users will
authorize clients with one or more scopes that determine how much access they
have to data on the server.
The farmOS Default Roles module provides an OAuth scope for each of the default
roles: `farm_manager`, `farm_worker`, and `farm_viewer`.
If you are creating an integration with farmOS, see the
[OAuth](/development/module/oauth) page of the farmOS module development docs
for steps to create additional OAuth Scopes.
### Clients
An OAuth Client represents a 1st or 3rd party integration with the farmOS
server. Clients are uniquely identified by a `client_id` and can have an
optional `client_secret` for private integrations. Clients are configured to
allow only specific OAuth grants and can specify default `scopes` that are
granted when none are requested.
The core `farm_api_default_consumer` module provides a default client with
`client_id = farm` that can use the `password` and `refresh_token` grant. You
can use this client for general usage of the API, like writing a script that
communicates with *your* farmOS server, but it comes with limitations.
If you are creating an integration with farmOS, see the
[OAuth](/development/module/oauth) page of the farmOS module development docs
for steps to create an OAuth Client.
### Authorization Flows
The [OAuth 2.0 standards](https://oauth.net/2/) outline 3
[Oauth2 Grant Types](https://oauth.net/2/grant-types/) to be used in an OAuth2 Authorization Flow - They are
the *Authorization Code, Client Credentials* and *Refresh Token* Grants. The
[Authorization Code](#authorization-code-grant) and
[Refresh Token](#refreshing-tokens) grants are the only Authorization Flows recommended by
farmOS for use with 3rd party clients.
The **Client Credentials Grant** is often used for machine authentication not
associated with a user account. The client credentials grant should only be
used if a `client_secret` can be kept secret. If connecting to multiple
farmOS servers, each server should use a different secret. This is
challenging due to the nature of farmOS being a self-hosted application.
The [Password Credentials Grant](#password-credentials-grant) is a legacy
grant type that is
[no longer recommended](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-2.4).
Only use the Password Credentials Grant if the client can be trusted with a
farmOS username and password (this is considered *1st party*). Even if the
client is trusted, this grant type exposes the username and password and
results in an increased attack surface. In most cases the **Client Credentials
Grant** can be used with an OAuth client that is configured for each separate
integration.
#### Authorization Code Grant
The Authorization Code Grant is most popular for 3rd party client
authorization.
Requesting resources is a four step process:
**First**: the client sends a request to the farmOS server `/oauth/authorize`
endpoint requesting an `Authorization Code`. The user logs in and authorizes
the client to have the OAuth Scopes it is requesting.
Copy this link to browser -
http://localhost/oauth/authorize?response_type=code&client_id=farm&scope=farm_manager&redirect_uri=http://thirdparty/api/authorized&state=p4W8P5f7gJCIDbC1Mv78zHhlpJOidy
**Second**: after the user accepts, the server redirects
to the `redirect_uri` with an authorization `code` and `state` in the query
parameters.
Example redirect url from server:
http://thirdparty/api/authorized?code=9eb9442c7a2b011fd59617635cca5421cd089943&state=p4W8P5f7gJCIDbC1Mv78zHhlpJOidy
**Third**: copy the `code` and `state` from the URL into the body of a POST
request. The `grant_type`, `client_id`, `client_secret` and `redirect_uri` must
also be included in the POST body. The client makes a POST request to the
`/oauth/token` endpoint to retrieve an `access_token` and `refresh_token`.
$ curl -X POST -d "grant_type=authorization_code&code=ae4d1381cc67def1c10dc88a19af6ac30d7b5959&client_id=farm&redirect_uri=http://thirdparty/api/authorized" http://localhost/oauth/token
{"access_token":"3f9212c4a6656f1cd1304e47307927a7c224abb0","expires_in":"10","token_type":"Bearer","scope":"farm_manager","refresh_token":"292810b04d688bfb5c3cee28e45637ec8ef1dd9e"}
**Fourth**: the client sends the access token in the request header to access protected
resources. The header is an Authorization header with a Bearer token:
`Authorization: Bearer access_token`
$ curl --header "Authorization: Bearer b872daf5827a75495c8194c6bfa4f90cf46c143e" http://localhost/api
#### Password Credentials Grant
**NOTE:** The **Password Credentials Grant** is a legacy grant type that is
[no longer recommended](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-2.4).
Only use the **Password Grant** if the client can be trusted with a farmOS
username and password (this is considered *1st party*).
**NOTE:** The [Simple OAuth Password Grant](https://www.drupal.org/project/simple_oauth_password_grant)
module must be enabled to use the password grant.
The Password Credentials Grant uses a farmOS `username` and `password` to
retrieve an `access_token` and `refresh_token` in one step. For the user, this
is the simplest type of *authorization.* Because the client can be trusted with
their farmOS Credentials, a users `username` and `password` can be collected
directly into a login form within the client application. These credentials are
then used (not stored) to request tokens which are used for *authentication*
with the farmOS server and retrieving data.
Requesting protected resources is a two step process:
**First**, the client sends a POST request to the farmOS server `/oauth/token`
endpoint with `grant_type` set to `password` and a `username` and `password`
included in the request body.
$ curl -X POST -d "grant_type=password&username=username&password=test&client_id=farm&scope=farm_manager" http://localhost/oauth/token
{"access_token":"e69c60dea3f5c59c95863928fa6fb860d3506fe9","expires_in":"300","token_type":"Bearer","scope":"farm_manager","refresh_token":"cead7d46d18d74daea83f114bc0b512ec4cc31c3"}
**second**, the client sends the `access_token` in the request header to access protected
resources. The header is an Authorization header with a Bearer token:
`Authorization: Bearer access_token`
$ curl --header "Authorization: Bearer e69c60dea3f5c59c95863928fa6fb860d3506fe9" http://localhost/api
#### Refreshing Tokens
The `refresh_token` can be used to retrieve a new `access_token` if the token
has expired.
It is a one step process:
The client sends an authenticated request to the `/oauth/token`endpoint with
`grant_type` set to `refresh_token` and includes the `refresh_token`,
`client_id` and `client_secret` in the request body.
$ curl -X POST -H 'Authorization: Bearer ad52c04d26c1002084501d28b59196996f0bd93f' -d 'refresh_token=52e7a0e12e8ddd08b155b3b3ee385687fef01664&grant_type=refresh_token&client_id=farm&client_secret=client_secret' http://localhost/oauth/token
{"access_token":"acdbfabb736e42aa301b50fdda95d6b7fd3e7e14","expires_in":"300","token_type":"Bearer","scope":"user_access","refresh_token":"b73f4744840498a26f43447d8cf755238bfd391a"}
The server responds with an `access_token` and `refresh_token` that can be used
in future requests. The previous `access_token` and `refresh_token` will no
longer work.

View File

@@ -0,0 +1,442 @@
# API Changes
## 3.x vs 2.x
The [Simple OAuth](https://www.drupal.org/project/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](https://www.drupal.org/node/3395697)
- Log `timestamp` is marked as `required` 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](https://drupal.org/project/restws)
module, which provided API endpoints for each entity type (asset, log, taxonomy
term, etc).
farmOS 2.x uses the new [JSON:API](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module)
module included with Drupal core, which follows the [JSON:API](https://jsonapi.org/)
specification for defining API resources.
The root API endpoint is `/api`.
### JSON Schema
farmOS 2.x also provides [JSON Schema](https://json-schema.org/) 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](/development/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:
```json
{
"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`:
```json
{
"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](https://en.wikipedia.org/wiki/Universally_unique_identifier)
(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](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/filtering)
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](https://drupal.org/project/farm_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` (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` 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](https://drupal.org/project/restws_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](https://www.drupal.org/project/restws_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](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/file-uploads)
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

View File

@@ -0,0 +1,75 @@
# API
farmOS provides an API that other applications and systems can use to read and
write records via HTTP requests.
## Client Libraries
Client libraries are available for interacting with the farmOS API:
- [farmOS.js](https://github.com/farmOS/farmOS.js) - [documentation](https://farmos.org/development/farmos-js/)
- [farmOS.py](https://github.com/farmOS/farmOS.py) - [documentation](https://farmos.org/development/farmos-py/)
## JSON:API
farmOS adheres to the [JSON:API](https://jsonapi.org/) specification for
defining API resources and uses the [JSON:API](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module)
module included with Drupal core.
Refer to the Drupal JSON:API [documentation](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module)
for all features including:
- [Core concepts](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/core-concepts)
- [Filtering](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/filtering)
- [Pagination](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/pagination)
- [Sorting](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/sorting)
- and many more.
### Endpoints
farmOS uses the `/api` path prefix for all JSON:API endpoints.
A root `/api` endpoint provides information meta information about the
authenticated user and the farmOS server:
```json
"meta": {
"links": {
"me": {
"meta": {
"id": "e437f724-45cd-4c36-852b-e91f7daec5fd"
},
"href": "https://farmos.site/api/user/user/e437f724-45cd-4c36-852b-e91f7daec5fd"
}
},
"farm": {
"name": "Farm Name",
"url": "https://farmos.site",
"version": "3.x",
"system_of_measurement": "metric"
}
}
```
The root `/api` endpoint also provides 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).
### IDs
farmOS assigns [UUIDs](https://en.wikipedia.org/wiki/Universally_unique_identifier)
(universally unique identifiers) to all resources, and uses them in the API.
## JSON Schema
[JSON Schema](https://json-schema.org/) is used to describe the available API
resources.
To begin exploring the farmOS API schema, visit `/api/schema`. From there, you
can traverse a graph of interconnected schemas describing the entire API.