Moved wiki to main repository instead of wiki as this is a documentation repository.

Mark van der Wal 2020-05-05 20:45:25 +02:00
parent 1315978043
commit da2f42ee74
20 changed files with 2113 additions and 2 deletions

1
.gitignore vendored 100644
View File

@ -0,0 +1 @@
.idea/

14
Authentication.md 100644
View File

@ -0,0 +1,14 @@
## Autentication
Farmmaps uses OpenID-connect: https://openid.net/connect/
It is recommended to use a library to facilitate the authentication.
To get the openid configuration call the following url: https://accounts.farmmaps.awtest.nl/.well-known/openid-configuration
The user could also use the openid-configuration to handle authentication by themselves.
https://identitymodel.readthedocs.io/en/latest/native/overview.html
The token received needs to be used in the request header.
>'Authorization': 'bearer {token}'
The token can also easily be created through the swagger documentation:
https://farmmaps.awtest.nl/swagger/index.html

132
Create-Cropfield.md 100644
View File

@ -0,0 +1,132 @@
## Create cropfield with the farmmaps API
If there aren't any relevant cropfields in FarmMaps, you can create them yourself by executing the following steps:
* Execute the following REST call to create the 'my_drive' item which contains the needed itemcode:
> Request
```
GET /api/v1/folders/my_drive
```
> Response 200 Succes
```javascript
{
"url": "string",
"code": "string",
"name": "string",
"created": "2019-12-18T09:49:35.741Z",
"updated": "2019-12-18T09:49:35.741Z",
"dataDate": "2019-12-18T09:49:35.741Z",
"itemType": "string",
"sourceTask": "string",
"size": 0,
"state": 0,
"thumbnail": true
}
```
* Create a 'FOLDER' item as a child of the 'my_drive' item.
>Request
```javascript
POST /api/v1/items
{
"parentCode": "{my_drive_code}",
"itemType": "FOLDER",
"name": "string",
"data": {},
"dataDate": "2019-12-18T09:59:18.893Z",
"geometry": {},
"tags": [
"string"
]
}
```
> Response 201 Created
```javascript
{
"parentCode": "string",
"geometry": {},
"data": {},
"tags": [
"string"
],
"url": "string",
"code": "string",
"name": "string",
"created": "2019-12-18T10:16:21.455Z",
"updated": "2019-12-18T10:16:21.455Z",
"dataDate": "2019-12-18T10:16:21.455Z",
"itemType": "string",
"sourceTask": "string",
"size": 0,
"state": 0,
"thumbnail": true
}
```
Response 401 Not authenticated
Response 403 No WRITE permissions in parent item
Response 404 Parent Item not found
* Create a 'vnd.farmmaps.itemtype.cropfield' item as a child of the 'FOLDER' item.
Needs to contain dataDate and dataEndDate to specify cropfield season.
dataDate needs to be before dataEndDate and cannot be the same day.
> Request
```javascript
POST /api/v1/items
{
"parentCode": "{FOLDER_item_code}",
"itemType": "vnd.farmmaps.itemtype.cropfield",
"name": "cropfield for VRA",
"dataDate": "2019-1-18T10:16:21.455Z",
"dataEndDate": "2019-12-18T10:16:21.455Z",
"data": {},
"geometry": {"type":"Polygon","coordinates":[[[6.09942873984307,53.070025028087],[6.09992507404607,53.0705617890585],[6.10036959220086,53.0710679529031],[6.10065149010421,53.0714062774307],[6.10087493644271,53.0716712354474],[6.10091082982487,53.0716936039203],[6.10165087441291,53.0712041549161],[6.10204994718318,53.0709349338005],[6.10263143118855,53.0705789370018],[6.10311578125011,53.0702657538294],[6.10331686552072,53.0701314102389],[6.103326530575,53.070119463569],[6.10309137950343,53.0699829669055],[6.10184241586523,53.0692902201371],[6.10168497998891,53.0691984306747],[6.10092987659869,53.0694894453514],[6.09942873984307,53.070025028087]]]}
}
```
> Response 201 Created
```Javascript
{
"parentCode": "string",
"geometry": {},
"data": {},
"tags": [
"string"
],
"url": "string",
"code": "string",
"name": "string",
"created": "2019-12-18T10:16:21.455Z",
"updated": "2019-12-18T10:16:21.455Z",
"dataDate": "2019-12-18T10:16:21.455Z",
"itemType": "string",
"sourceTask": "string",
"size": 0,
"state": 0,
"thumbnail": true
}
```
* Execute the workflow task with the cropfield item code.
This steps makes sure that FarmMaps aggregates all needed data for the cropfield.
> Request
```javascript
POST /api/v1/items/{code}/tasks
{
"taskType": "vnd.farmmaps.task.workflow"
}
```
> Response 201
```javascript
{
"code": "string",
"taskType": "vnd.farmmaps.task.workflow",
"delay": "",
"attributes": {
"additionalProp1": "string",
"additionalProp2": "string",
"additionalProp3": "string"
}
}
```
Response 400 Tasktype not found
Response 401 Not authenticated
Response 403 No WRITE permissions in item
Response 404 Item not found

30
Create-Taskmap.md 100644
View File

@ -0,0 +1,30 @@
## Create taskmap
The user can use the "ItemTask" API to execute the TaskmapTask with the item code which contains the tiff data in {code}.
> Request
```javascript
POST /api/v1/items/{code}/tasks
{
"taskType": "vnd.farmmaps.task.taskmap"
}
```
> Response 201
```javascript
{
"code": "string",
"taskType": "vnd.farmmaps.task.taskmap",
"delay": "",
"attributes": {
"additionalProp1": "string",
"additionalProp2": "string",
"additionalProp3": "string"
}
}
```
Response 400 Tasktype not found
Response 401 Not authenticated
Response 403 No WRITE permissions in item
Response 404 Item not found
This will create the item with shape data as a sibling of the input item.

View File

@ -0,0 +1,215 @@
## Creating a cropfield
This page explains what a cropfield is, and how to create one through the API.
Agricultural datasets generally refer to a specif crop, at a specific location at a specific time.
Therefore, we need to create a "Cropfield" item, to define this location and a timeframe our data relates to.
A cropfield provides a convienient way to group all data for a crop grown on a specific plot during a season.
Farmmaps also uses the cropfield to collect and prepare context data such as weather, satelite imagery etc.
To create a cropfield we:
* Get the parent folder to place the cropfield under
* Create a folder under this element (optional)
* Create the cropfield
**Prerequisites**
To create a cropfield we need:
* an acces token
* coordinates of the cropfield (what points define the plot contour)
* a startdate and an end date (what timeframe does this data aply to)
### Get parent element
First, we'll get the parent code needed to place the cropfield in the hierarchy.
**Request**
Replace `<acces token>` with your actual token.
```http
GET https://farmmaps.awacc.nl/api/v1/folders/my_drive? HTTP/1.1
Host: farmmaps.awacc.nl
Accept: application/json
Authorization: Bearer <access token>
```
**Response**
The response will be something similar to:
```http
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Tue, 21 Apr 2020 09:57:07 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-store,no-cache
Pragma: no-cache
Content-Encoding: br
Vary: Accept-Encoding
{
"url":"/api/v1/folders/f25d8765a1cd407cb235961c73c268cf:USER_FILES",
"code":"f25d8765a1cd407cb235961c73c268cf:USER_FILES",
"name":"My Drive",
"created":"2019-09-25T19:39:33.841835",
"updated":"2019-09-25T19:39:33.841835",
"itemType":"ROOT_FOLDER",
"size":0,
"state":0,
"thumbnail":false
}
```
So the `parentcode` we need is **"f25d8765a1cd407cb235961c73c268cf:USER_FILES"**
You can also find the code of a folder by browsing the folders in your FarmMaps account through the web interface.
The item code is the last part of the URL.
### Create folder
Depending on how you want to organise things, you might choose to make a separate folder for the cropfield.
A folder can be created by creating an item with itemType `FOLDER`.
> **Note:** At the moment, subfolders can not be created directly under the root folder, create a folder through the web interface first.
**Request**
```http
POST /api/v1/items HTTP/1.1
Accept: application/json
Authorization: Bearer <access token>
Content-Type: application/json
Cache-Control: no-cache
Host: farmmaps.awacc.nl
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 210
{
"parentCode": "f25d8765a1cd407cb235961c73c268cf:USER_FILES",
"itemType": "FOLDER",
"name": "My_new_folder",
"data": {},
"dataDate": "2020-04-24T09:59:18.893Z",
"geometry": {},
"tags": [ "string" ]
}
```
When the folder is created successfully we should recieve something like this:
**Response**
```http
{
"parentCode": "string",
"geometry": {},
"data": {},
"tags": [
"string"
],
"url": "string",
"code": "string",
"name": "My_new_folder",
"created": "2019-12-18T10:16:21.455Z",
"updated": "2019-12-18T10:16:21.455Z",
"dataDate": "2019-12-18T10:16:21.455Z",
"itemType": "string",
"sourceTask": "string",
"size": 0,
"state": 0,
"thumbnail": true
}
```
### Create the cropfield
Now we can create the cropfield. We do so by setting `"itemType": "vnd.farmmaps.itemtype.cropfield"` and adding data to the geometry parameter.
Generally, a cropfield contour would be defined as a polygon, so we add `"type":"Polygon" and all the coordinates.
We also need to specify a `dataDate` and a `dataEndDate` to indicate the the timeframe of the growing season.
The `dataDate` needs to be before `dataEndDate` and cannot be on the same day.
**Request**
```http
POST /api/v1/items HTTP/1.1
Accept: application/json
Authorization: Bearer <acces token>
Content-Type: application/json
Cache-Control: no-cache
Host: farmmaps.awacc.nl
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 916
{
"parentCode": "6601a06d812b40f9830c9fe4e63b1944",
"itemType": "vnd.farmmaps.itemtype.cropfield",
"name": "cropfield for VRA",
"dataDate": "2019-1-18T10:16:21.455Z",
"dataEndDate": "2019-12-18T10:16:21.455Z",
"data": {},
"geometry": {"type":"Polygon","coordinates":[[[6.09942873984307,53.070025028087],[6.09992507404607,53.0705617890585],[6.10036959220086,53.0710679529031],[6.10065149010421,53.0714062774307],[6.10087493644271,53.0716712354474],[6.10091082982487,53.0716936039203],[6.10165087441291,53.0712041549161],[6.10204994718318,53.0709349338005],[6.10263143118855,53.0705789370018],[6.10311578125011,53.0702657538294],[6.10331686552072,53.0701314102389],[6.103326530575,53.070119463569],[6.10309137950343,53.0699829669055],[6.10184241586523,53.0692902201371],[6.10168497998891,53.0691984306747],[6.10092987659869,53.0694894453514],[6.09942873984307,53.070025028087]]]}
}
```
**Response**
When the cropfield is created, it should be visible through the FarmMaps web interface (under "My Drive" in the respective parent folder).
We should have the following response:
```http
HTTP/1.1 201 Created
Server: nginx/1.14.0 (Ubuntu)
Date: Fri, 24 Apr 2020 08:56:45 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-store,no-cache
Pragma: no-cache
Content-Encoding: br
Location: /api/v1/items/8ecbaa2d85d5484db7f16b281b7cd013
Vary: Accept-Encoding
{
"parentCode":"6601a06d812b40f9830c9fe4e63b1944",
"geometry": {
"type":"Polygon",
"coordinates":[[
[6.09942873984307,53.070025028087],
[6.09992507404607,53.0705617890585],
[6.10036959220086,53.0710679529031],
[6.10065149010421,53.0714062774307],
[6.10087493644271,53.0716712354474],
[6.10091082982487,53.0716936039203],
[6.10165087441291,53.0712041549161],
[6.10204994718318,53.0709349338005],
[6.10263143118855,53.0705789370018],
[6.10311578125011,53.0702657538294],
[6.10331686552072,53.0701314102389],
[6.103326530575,53.070119463569],
[6.10309137950343,53.0699829669055],
[6.10184241586523,53.0692902201371],
[6.10168497998891,53.0691984306747],
[6.10092987659869,53.0694894453514],
[6.09942873984307,53.070025028087]]
]},
"data":{},
"tags":[],
"isEditable":false,
"url":"/api/v1/items/8ecbaa2d85d5484db7f16b281b7cd013",
"code":"8ecbaa2d85d5484db7f16b281b7cd013",
"name":"cropfield for VRA",
"created":"2020-04-24T08:56:45.3727807Z",
"updated":"2020-04-24T08:56:45.3727807Z",
"dataDate":"2019-01-18T10:16:21.455Z",
"itemType":"vnd.farmmaps.itemtype.cropfield",
"size":0,
"state":0,
"thumbnail":false
}
```
**Troubleshooting**
|Status code|Description|
|---|---|
|201|Cropfield created successfully|
|401|Error: not authenticated|
|403|Error: No write permissions in parent item|
|404|Error: Parent item not found|
Now that the cropfield has been created, we can start the processing by running a task.
This will collext all context data for the cropfield.
We need the ItemCode of the cropfield to start the task so keep this at hand.

View File

@ -0,0 +1,26 @@
# Get an access token
This page explains how to get an access token, this token needs to be sent along when sending requests to the REST API.
Please follow the steps below
1. Go to the swagger documentation: [https://farmmaps.awacc.nl/swagger/index.html](https://farmmaps.awacc.nl/swagger/index.html)
2. Click "Authorize" and check the "Scopes" checkbox, click authorize again.
3. You will now be redirected to the FarmMaps OpenID login form, enter your details (akkerweb account, acceptation or test) and login.
4. Once logged in, you will automatically be redirected back to swagger again.
5. Close the "Available authorizations" popup.
6. Expand one of the items listed, for example "CodeListItem".
7. Click "Try it Out" and then "Execute"
8. Under "Responses" the curl command lists the access token after `-H "Authorization: Bearer `:
```
curl -X GET "https://farmmaps.awacc.nl/api/v1/codelistitems" -H "accept: application/json" -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IkNERkM3M0I0NzY0Q0M5RTYxQTVDRjg3OEM5MDlFRUU0ODFFODk5MzEiLCJ0eXAiOiJhdCtqd3QiLCJ4NXQiOiJ6Znh6dEhaTXllWWFYUGg0eVFudTVJSG9tVEUifQ.eyJuYmYiOjE1ODcxMzE4ODMsImV4cCI6MTU4NzEzNTQ4MywiaXNzIjoiaHR0cHM6Ly9hY2NvdW50cy5mYXJtbWFwcy5hd2FjYy5ubCIsImF1ZCI6ImFwaSIsImNsaWVudF9pZCI6ImZhcm1tYXBzYWNjX3N3YWdnZXIiLCJzdWIiOiJtYWlsdG86YXVrZUBzaW1wZWx3ZWJkZXNpZ24ubmwiLCJhdXRoX3RpbWUiOjE1ODcxMzE4ODIsImlkcCI6ImxvY2FsIiwic2NvcGUiOlsiYXBpIl0sImFtciI6WyJwd2QiXX0.HOnc6ohPFljzPRXMpDnDMXlmlYCb5SBrNB3OMrpjAGx_TSES-ZJ8QuOwyeVLEn4LG0USkMzKZpR4MGAZvkN-5CgLu2unFWHjVBU_tY16QBg7pOnd-ZdXbMojINFk05EIFXEL2vBMWV1i3pxQVFK3jb7ybt_Lkw-X-2PwkcwaJk72aNY05pBswhyEr1PqSlVc5jOZuJzdzB6q17FRkCvxtIGmM-aSQpCozMdwD1CTu7ZBM_hvtFSmmkyWLh6PeFsj65ls18fWuBU_ekV3Djbj786GXRYUWS2_ObTbzfc0rEyy7fzesI1Jty6iYT6ZkUGl9NRt670wg7QZi7-qFRxglX6uU2JpW6veTBNkBgmDiJqbaSaJt-ADn32BGDjdSePxeD1shbeNAqYun9UkTn81PBptp3WpAd4hDuziL2k_m5IpryznJQu3G42Q27F3roFi4E1t7kcJNUs0umGPx_JTdMiipG-QOV20U4BnIOwH0qbxjUumEs24qCpT0YGArblK60a4_XFX6qinkKtUi4WfE5mHJnCF3y1iJ0hv0eGixzVLPGIcqTlSIFDIUhj_wzHSX-c5fXKIv-n9mE6_TBUoGZGdH2EAXq_ohTN_Ipmp2cmw7u7tFWOsPB-7UQzxh2dHDgtJ-V9u02j4jbCflRKuN7CQ5DB3Yvnfg2FuCoOSngQ"
```
So the access token is:
```
eyJhbGciOiJSUzI1NiIsImtpZCI6IkNERkM3M0I0NzY0Q0M5RTYxQTVDRjg3OEM5MDlFRUU0ODFFODk5MzEiLCJ0eXAiOiJhdCtqd3QiLCJ4NXQiOiJ6Znh6dEhaTXllWWFYUGg0eVFudTVJSG9tVEUifQ.eyJuYmYiOjE1ODcxMzE4ODMsImV4cCI6MTU4NzEzNTQ4MywiaXNzIjoiaHR0cHM6Ly9hY2NvdW50cy5mYXJtbWFwcy5hd2FjYy5ubCIsImF1ZCI6ImFwaSIsImNsaWVudF9pZCI6ImZhcm1tYXBzYWNjX3N3YWdnZXIiLCJzdWIiOiJtYWlsdG86YXVrZUBzaW1wZWx3ZWJkZXNpZ24ubmwiLCJhdXRoX3RpbWUiOjE1ODcxMzE4ODIsImlkcCI6ImxvY2FsIiwic2NvcGUiOlsiYXBpIl0sImFtciI6WyJwd2QiXX0.HOnc6ohPFljzPRXMpDnDMXlmlYCb5SBrNB3OMrpjAGx_TSES-ZJ8QuOwyeVLEn4LG0USkMzKZpR4MGAZvkN-5CgLu2unFWHjVBU_tY16QBg7pOnd-ZdXbMojINFk05EIFXEL2vBMWV1i3pxQVFK3jb7ybt_Lkw-X-2PwkcwaJk72aNY05pBswhyEr1PqSlVc5jOZuJzdzB6q17FRkCvxtIGmM-aSQpCozMdwD1CTu7ZBM_hvtFSmmkyWLh6PeFsj65ls18fWuBU_ekV3Djbj786GXRYUWS2_ObTbzfc0rEyy7fzesI1Jty6iYT6ZkUGl9NRt670wg7QZi7-qFRxglX6uU2JpW6veTBNkBgmDiJqbaSaJt-ADn32BGDjdSePxeD1shbeNAqYun9UkTn81PBptp3WpAd4hDuziL2k_m5IpryznJQu3G42Q27F3roFi4E1t7kcJNUs0umGPx_JTdMiipG-QOV20U4BnIOwH0qbxjUumEs24qCpT0YGArblK60a4_XFX6qinkKtUi4WfE5mHJnCF3y1iJ0hv0eGixzVLPGIcqTlSIFDIUhj_wzHSX-c5fXKIv-n9mE6_TBUoGZGdH2EAXq_ohTN_Ipmp2cmw7u7tFWOsPB-7UQzxh2dHDgtJ-V9u02j4jbCflRKuN7CQ5DB3Yvnfg2FuCoOSngQ
```
### Note
* The access token expires after one hour.

38
FarmMapsLibs.md 100644
View File

@ -0,0 +1,38 @@
## FarmMapsLibs
***-container** types dynamically loads components.
**For FarmMaps Openlayer feature items**
* feature-list
* feature-list-container
* feature-list-feature
* feature-list-feature-container
Examples:
* croppingscheme
* cropfield
**For FarmMaps items details tile/info**
* item-list
* item-list-item-container
* item-list-item
Examples:
* shadow
* height
* bofek
* etc...
**For FarmMaps item details page**
* selected-item
* selected-item-container
Examples:
* cropfield
* geotiff
* shape
**Other**
* item-widget-list
Examples:
* Weather

View File

@ -0,0 +1,30 @@
# Integrating FarmMaps OpenID Connect
Farmmaps uses OpenID Connect (OIDC).
This page lists the information needed to integrate OpenID connect into your application.
Note that for testing purposes it is quicker to just [generate an access token]() instead of implementing a complete integration.
Please see [https://openid.net/connect/](https://openid.net/connect/) if you are not familiar with OpenID Connect.
To integrate OIDC, it is recommended to use a (certified) library/implementation for your language of choice:
* [https://openid.net/developers/libraries/](https://openid.net/developers/libraries/)
When developing in C# / .NET, the recommended library is the `IdentityModel OpenID client`:
* [https://identitymodel.readthedocs.io/en/latest/native/overview.html](https://identitymodel.readthedocs.io/en/latest/native/overview.html)
To configure your library with the right settings, you'll need the Farmmaps OpenID configuration:
* https://accounts.farmmaps.awtest.nl/.well-known/openid-configuration
#### Note
* At the moment FarmMaps only supports the OpenID Connect **"explicit" flow type**.
More about flow types can be found [here](https://www.scottbrady91.com/OpenID-Connect/OpenID-Connect-Flows).
* At the moment, FarmMaps does not support dynamic client registration.
Please request a client id from one of our developers when you need one for your application.
In the meantime, it is recommended to simply [generate an access token]() to explore the REST API.

86
Main-components.md 100644
View File

@ -0,0 +1,86 @@
# FarmMaps main components
This page documents the main components of FarmMaps, to provide a general understanding of how data is stored, processed and how to access this data.
### Main data structure
Farmmaps uses a few basic objects to organise the data that is put into it.
The following hierarchy (starting with the highest parent element) can be used as a reference:
|Element|Description|
|----|---|
|Farm| The highest level grouping element, the data is grouped by farm.|
|Cropyear|All the crop's grown on the different fields of the farm are grouped in a cropyear.|
|Plot|All different crop's grown in the different growing seasons/or years are grouped by plot.|
|Cropfield| For each crop in a specific growing year/season and on a specific plot, a cropfield is created. All data related to that specific cropfield can then be grouped under this element. This can be data such as task maps, yield maps, NDVI maps or drone images.|
Most agricultural data has a strong link to one or more of the elements above. A few examples:
- An electrical conductivity map, which is related to the plot (electrical conductivity is a soil parameter).
- A yield map, which is related to the cropfield (yields can vary per year, per crop etc.)
### Data storage
On the server, FarmMaps stores data in 2 ways. Raw data is stored in files, metadata is stored in the database.
#### File storage (raw data).
The primary method is through files. Each dataset is saved in a file on disk and given a unique identifier.
Generally, this is the raw data, and this data does not contain so called "meta data".
For example, let's say we have a `.csv` file like this:
```
timestamp,latitude,longitude,altitude,speed,direction,engine torque
24-11-2019 13:43:20,53.12694303,6.339856608,-25.649,0.099,235.3399,24
24-11-2019 13:43:19,53.12694303,6.339856608,-25.361,0.693,25.8694,24
24-11-2019 13:43:18,53.12694303,6.339856608,-23.017,0.793,38.8679,42
24-11-2019 13:43:17,53.12694303,6.339856608,-25.41,0.92,60.8391,46
24-11-2019 13:43:10,53.12694303,6.339856608,-11.667,0.029,139.1908,50
24-11-2019 13:43:09,53.12694303,6.339856608,-11.558,0.043,198.0093,45
24-11-2019 13:43:08,53.12694303,6.339856608,-11.426,0.034,183.7946,23
24-11-2019 13:43:07,53.12694303,6.339856608,-11.243,0.013,144.7128,35
24-11-2019 13:43:06,53.12694303,6.339856608,-11.248,0.022,135.7003,29
```
#### Database storage (meta-data)
For each file in the file storage, a database record exists with a reference to the file.
The database record contains the metadata of the file, so files can easily be found by the system.
This metadata describes how the data in the raw file should be interpreted.
While the file example above might look easy to understand, it becomes a little bit unclear what it actually means when we take a better look at it.
The first line specifies the column headers:
```
timestamp,latitude,longitude,altitude,speed,direction,engine torque
```
While it gives some information, this information is hard to relate to other data because some information is missing.
When we look at data in the `speed` column, we can se that it changes, but we do not know how it was measured.
Useful metadata here would be the unit of measurement, for example `km/hour` or `meters/second`.
While FarmMaps does currently not allow you to specify this by hand as a user, it is important to realise metadata might need to be provided to have the data properly processed by FarmMaps.
### Endpoints
To upload and download data to and from FarmMaps, two API endpoints are provided.
The first and primary API is the REST API for uploading an downloading files.
The second endpoint is the MQTT API, for pushing more stream like data.
For the time being, we recommend using the REST API as your primary choice.
#### REST Endpoint
The REST API is the primary API for FarmMaps and allows you to:
* Upload data files
* Download data files
* Run a processing task (i.e. convert a file into another format or similar)
* Run other tasks (create a taskmap, create cropfield etc.)
* Monitor the progress of the processing tasks
Several how-to's can be found in the [examples folder][/src/branch/master/examples/]
There's also swagger based reference of the [REST API](https://farmmaps.awacc.nl/swagger/index.html)
#### MQTT Endpoint
The MQTT Endpoint provides a way to input more stream like data like a live GPS location, or live temperature measurement to FarmMaps.
This endpoint is still under development. If you would like to build on top of this endpoint, please contact the FarmMaps development team.
As a reference, please also see [Sending data to MQTT](/src/branch/master/Message-Queue-Endpoint).
### Data processing infrastructure
To process the data that is provided through the endpoints, FarmMaps uses queues and workers to manage the execution of these tasks.
How this works is described in [the workflow article](/src/branch/master/Workflow)
### Viewer
To visualize all data in the FarmMaps backend, FarmMaps integrates it's own viewer.
This viewer is available as an open source project and can be found in the [FarmMapsLibs Repository](https://git.akkerweb.nl/FarmMaps/FarmMapsLib).
There's also a separate documentation page which can be found [here](/src/branch/master/FarmMapsLibs). [under development]

View File

@ -0,0 +1,200 @@
## Sending data to the MQTT endpoint
This documentation page provides the basics on how to access the MQTT endpoint of FarmMaps, using Python code for examples.
The same workflow can be followed for different languages, as long as there's a MQTT client and a Protobuf library for the language you are using.
FarmMaps provides an MQTT endpoint to allow your application to send signals to FarmMaps, and listen for events.
These signals are collected in a "message queue".
If you are not familiar with anything mentioned, please see the [FAQ](#faq) at the end.
### Prerequisites
To follow along with the examples, you need:
* Access to the FarmmMaps MQTT broker (user, password), these can be requested **here**
* To have Python 3.7 or higher installed.
* To come up with a unique identifier for your sensors, to use in the `URN`.
Generally the URN is composed of the company or brand name and a device serial number like so:
```python
"urn:dev:<company-name>:<device-serial-number>"
```
To run the python example code you also need to install the `paho-mqtt` and the `protobuf` modules.
### Workflow
The general workflow for pushing data to the FarmMaps MQTT endpoint consists of:
* Preparing your data as a protobuf message
* Connecting to the MQTT Broker
* Publishing the message and waiting for confirmation.
* Closing the connection
To be able to publish data to the broker, you need an username and password, and posibly a dedicated topic for your data.
An account can be requested through email from XXXXX. This user is only for the broker, and can not be used for the other API's.
Generally, one user is provided per application (so no individual users for different sensors within the same application).
### Settings
To connect to the MQTT Broker, we'll use the following settings:
| Parameter | Default | Description |
| :---: | :------------------------------------------: | --- |
| CLIENT_ID | - | This ID is used to identify the connecting party (your software) to the broker, please use your company or brand name. |
| USER | - | Your username at the FarmMaps broker. |
| PWD | - | Your password at the FarmMaps broker. |
| HOST | `farmmaps.awtest.nl` | The address of the FarmMaps broker. |
| PORT | `1883` | The port number of the FarmMaps broker. |
| KEEPALIVE | `60` | Number of seconds to maintain the connection, even if no messages are published.
| TOPIC | `trekkerdata/sensors` | The topic to publish the messages to at the broker. |
For preparing the message, we'll use the following settings:
| Parameter | Default | Description |
| :---: | :---------------------------------------------------------------: | --- |
| META_DATA_URL | - | HTTP adress where a JSON metadata file for the messages is provided (by the data source). |
| BASE_DEV_URN | `urn:dev:<company-name>:<device-serial-number>` | To identify each unique device from different parties, FarmMaps uses a Universal Resource Name (URN). Farmmaps uses this code to link devices and data to their owners and manage access to data devices. |
All settings are required except for the `META_DATA_URL`, this parameter is optional.
### Connecting to the MQTT Broker
First, we will create a MQTT client to connect to the FarmMaps MQTT broker:
```python
#import mqtt client
from farmmaps import mqtt
#MQTT connection settings
CLIENT_ID = '<your client id>'
USER = "<your username>"
PWD = "<your password here>"
HOST = "farmmaps.awacc.nl"
PORT = 1883
KEEPALIVE = 60
TOPIC = "<company-name>/<topic-name>"
#set up MQTT client
mqtt_client = mqtt.create_client(CLIENT_ID, USER, PWD, HOST, PORT, KEEPALIVE)
```
### Preparing your data as a protobuf message
Farmmaps uses protobuf to specify a structure for the messages published in MQTT.
More information on protobuf can be found at [Google Developer Documentation](https://developers.google.com/protocol-buffers/docs/overview).
Python objects can easily be converted to protobuf messages and back (when recieving messages from the broker).
The message structure for the data can be found in `farmmaps/farmmaps.proto`, and is shown below.
**Datastructure explained**
The main message is the Datapoint object, containing time, location, machine-id and a reference to metadata.
Then, there is a `sensors` parameter, which holds a dictionary of `SensorType` objects.
Each `SensorType` holds a key and a value, where the key identifies the Sensortype, and the value is the value of the sensor.
Finally, there's an optional `metadata_url` parameter that specifies where FarmMaps can get metadata.
This is data that specifies how the values for each sensortype are to be interpreted.
```
syntax = "proto2";
package farmmaps;
message DataPoint {
required string machine_id = 1;
required int64 ts = 2;
required float lat = 3;
required float lon = 4;
optional float altitude = 5;
optional float heading = 6;
optional float speed = 7;
message SensorType {
required string key = 1;
required float value = 2;
}
repeated SensorType sensors = 8;
optional string metadata_url = 9;
}
```
This `.proto` file is processed by protobuf and converted to a python class.
This class can be found in `farmmaps/farmmaps_pb2.py` and should not be edited directly.
Edit the proto file and regenerate when you need to change the format.
In our code we can then use the protobuff class like so:
```python
#import protobuf class
from farmmaps import farmmaps_pb2
# message settings
META_DATA_URL = 'http://68.183.9.30:8082/v3/meta/sensors'
BASE_DEV_URN = 'urn:dev:nl.trekkerdata:%s'
#create sample data for message
device_id = "ib017"
timestamp = 1582731928 #epoch timestamp
longitude = 6.07206584
latitude = 52.959456183
altitude = 7.3
heading = 94.8534
speed = 0.026
sensordata = {"spn_898": 0, "spn_518": 0, "spn_513": 50, "spn_190": 1000}
# create empty protobuf message
msg = farmmaps_pb2.DataPoint()
# assign values to message properties
msg.machine_id = BASE_DEV_URN % (device_id)
msg.ts = timestamp
msg.lon = longitude
msg.lat = latitude
msg.altitude = altitude
msg.heading = heading
msg.speed = speed
for key, value in sensordata.items():
measurement = msg.sensors.add()
measurement.key = key
measurement.value = value
```
In case you want to modify the structure of the object, the `.proto` can be modified, and the python module needs to be regenerated.
For now, we'll stick with the pregenerated protobuf class.
## References
* [Protobuf documentation](https://developers.google.com/protocol-buffers/docs/overview)
* [Paho MQTT documentation](https://www.eclipse.org/paho/clients/python/docs/)
## [FAQ](#faq)
#### How do I install the required Python modules?
This tutorial requires the `paho-mqtt` and `protobuf` modules.
These can be installed with the following commands:
**Windows command prompt:**
```
py -m pip install 'paho-mqtt==1.5.0'
py -m pip install 'protobuf==3.11.0'
```
**Linux terminal:**
```
python3 -m pip install 'paho-mqtt==1.5.0
python3 -m pip install 'protobuf==3.11.0'
```
#### What is a message queue?
A message queue is commonly used to make software programs able to send messages between eachother, and thereby making it easy for data to flow from one program into another. There are many variants of message queues, some popular names are Apache Kafka, MQTT and RabbitMQ.
In message queue systems there is usually one central "hub" called the broker or **"message broker"**. This broker holds all the messages. Usually, the messages are organised in groups called **"topics"**.
Now, there are two things that external services can do.
* An external service (like a sensor) could **publish a message to a certain topic**. For example, a temperature sensor would publish the temperature at a specific time and location to the "temperatureMeasurements" topic.
* An external service can **"subscribe" to this topic** by connecting to the broker. This service will then recieve every temperature measurement.
When the subscribed service temporarily disconnects from the broker, it will not recieve any messages, but the messages will remain stored at the broker. Depending on configuration, messages will be kept longer or shorter, or be deleted after they reach the subscribers but the intent is always to ensure the messages get from the **publisher** to the **subscriber**.
Setting communication between applications up like this makes things a lot more flexible than connecting systems directly and provides a central point for management of all communication.
#### What is protobuf?
To quote the Google Documentation:
> Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data think XML, but smaller, faster, and simpler.
> You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages.
More information can be found in the [protobuf documentation](https://developers.google.com/protocol-buffers/docs/overview).

View File

@ -0,0 +1,55 @@
## Polling task status
When a task is executed with the task API your retrieve a code.
This code can be used to poll the status of an item task execution.
The response 'message' field can contain a string message based on the context.
#### Get a list task of status for a given item
> Request
```javascript
GET /api/v1/items/{code}/tasks
```
> Response 200 OK
```javascript
[
{
"taskType": "string",
"code": "string",
"message": "string",
"state": "Error, Ok, Scheduled, Processing",
"started": "2020-03-20T11:13:20.568Z",
"finished": "2020-03-20T11:13:20.568Z"
},
{
"taskType": "string",
"code": "string",
"state": "Error, Ok, Scheduled, Processing",
}
]
```
Response 401 Not authenticated
Response 403 No READ permissions in parent item
Response 404 Parent Item not found
#### Get the status of a task for a given item and item task code
> Request
```javascript
GET /api/v1/items/{code}/tasks/{itemTaskCode}
```
> Response 200 OK
```javascript
{
"taskType": "string",
"code": "string",
"message": "string",
"state": "Error, Ok, Scheduled, Processing",
"started": "2020-03-20T11:13:20.568Z",
"finished": "2020-03-20T11:13:20.568Z"
}
```
Response 401 Not authenticated
Response 403 No READ permissions in parent item
Response 404 Parent Item not found

View File

@ -1,3 +1,73 @@
# Documentatie
## Farmmaps Documentation Overview
### The documentation is still work in progress and heavily subject to change!
This page provides an index of the available documentation for the FarmMaps platform.
## Getting started
The main starting point for Farmmaps API access is the REST API.
To get started, follow the steps below.
The workflow and high-level architecture FarmMaps are documented on the [Farmmaps Workflow](/src/branch/master/Workflow) and [FarmMaps Main Components](/src/branch/master/Main-components) pages.
### Environments
At the moment, FarmMaps provides two environments for development.
* https://farmmaps.awtest.nl (testing environment, data is not persistent)
* https://farmmaps.awacc.nl (acceptation environment, data IS persistent)
When developing your application, using the **acceptation environment is highly recommended**.
### Obtaining credentials
To get access to the API, you need an akkerweb development account (akkerweb development and farmmaps development use the same credentials).
These can be created at:
* https://awacc.nl (for the acceptation environment)
* https://awtest.nl (for the testing environment)
Once you have an account, you can create a JSON Web Token to authenticate at the API endpoint.
### Authentication & Authorization flow
FarmMaps uses Open ID Connect to provide user authentication and authorization services.
Open ID Connect (and OAuth beneath the surface) allows your application to access user information or data that is located at another service, without providing you the password to access the account. This is very useful if your application relies on data that needs to provided by this other service for your application to work.
So, in the authentication flow there are two parties:
* The OpenID Provider (OP), holding the accounts database and providing the authentication services.
* The Relying Party (RP), relying on authentication through the OP, to get access to the required data or endpoints.
The general flow (for FarmMaps) is as follows:
* The user is at your application
* Your application needs to access the farmmaps account of that user (i.e. to upload, modify or retrieve data)
* Your application creates an authentication request for the Open ID Provider.
* The user is redirected to the "Log in page" of the OpenID Provider.
* The user logs in at the login page.
* On succesfull login, the user is redirected back to your application and the OpenID Provider returns an access token.
Now that the user is back at your applicaiton and the application has an access token, it can then request resources from the OpenID provider.
For each request, the access token needs to be sent along. This access token provides proof that the person sending the request is allowed to access the request and is who he/she claims to be. FarmMaps uses [JWT](https://jwt.io/introduction/) as the format for the access token.
To continue please see one of the articles below:
- [Integrating FarmMaps Open ID Connect into your application](/src/branch/master/Integrating-FarmMaps-OIDC)
- [Creating an access token for testing.](/src/branch/master/Create-access-token)
## Using the FarmMaps API
Once you have an access token, you can start querying the API.
A reference of the API can be found on [the swagger page](https://farmmaps.awacc.nl/swagger)
The API basics are uploading files, creating items and and running tasks to modify or convert data.
For testing purposes, [Postman](https://www.postman.com) can be used to perform HTTP requests more easily.
We provide the following guides:
* [Uploading a file](/src/branch/master/Upload-a-file)
* [Creating a cropfield](/src/branch/master/Create-a-cropfield)
* [Running a task](/src/branch/master/Running-tasks)
Generally, tasks can be run in the same way.
However, each specific task has it's own inputs and properties.
How these work can be found in the use task examples below.
### <a name="task-examples"></a>Task examples
* [VRAPoten-API](/src/branch/master/VRAPoten-API)
* [VRANbs-API](/src/branch/master/VRANbs-API)
* [VRAHerbicide-API](/src/branch/master/VRAHerbicide-API)
All documentation currently resides in the [wiki](https://git.akkerweb.nl/FarmMaps/Documentatie/wiki)

266
Running-tasks.md 100644
View File

@ -0,0 +1,266 @@
# Running a task
This page documents how to run a task from the FarmMaps API.
Once you have uploaded some data and made sure the relevant cropfield is available, you can now instruct the system to start processing the data.
Processing data is done by running tasks. There are many different types of tasks to acomplish many different things such as:
* Identifying the type of file to start automatic processing
* Converting a CSV file to a Shapefile
* Filtering data for valid values
* Creating a taskmap of input data.
## Workflow task.
There is one special type of task, the `workflow` task.
When an item (i.e. file-upload, folder, cropfield etc.) is created there are certain processing tasks that can be done by "default".
As an example, for an uploaded file these tasks are:
- Re-assembling the part-chunks back into a single file
- Identifying the type of file, and how it should be processed.
For a cropfield there are slightly different tasks such as:
- retrieve AHN mapping data (cut-out from public height maps)
- retrieve soil compaction data (based on a public map)
- retrieve shadow mapping data (based on satellite imagery)
These steps are all defined in the workflow for each `itemType`.
So, once an item has been created, we can run the `workflow` task to execute the predefined tasks automatically.
### Example: Running the workflow task for a cropfield.
We run a task by adding the `taskType` to the body of the request, with `vnd.farmmaps.task.workflow` as the type of task.
The item that the task will be executed on is specified in the url by it's itemcode. Other types of tasks can be run by changing the taskType.
**Request**
```http
POST /api/v1/items/98a480ad8d7444a8a10ef547cd8594eb/tasks HTTP/1.1
Authorization: Bearer <access token>
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache
Host: farmmaps.awacc.nl
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 49
{
"taskType": "vnd.farmmaps.task.workflow"
}
```
**Response**
```http
HTTP/1.1 201 Created
Server: nginx/1.14.0 (Ubuntu)
Date: Sat, 25 Apr 2020 13:55:28 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-store,no-cache
Pragma: no-cache
Content-Encoding: br
Location: /api/v1/items/98a480ad8d7444a8a10ef547cd8594eb/tasks/52173fb5bf1146efa276ecfe1fda5f60
Vary: Accept-Encoding
{
"code":"52173fb5bf1146efa276ecfe1fda5f60",
"taskType":"vnd.farmmaps.task.workflow",
"attributes":{}
}
```
**Troubleshooting**
|Status code|Description|
|---|---|
|201|Task created|
|400|Error: Tasktype not found|
|401|Error: Not authenticated|
|403|Error: No WRITE permissions in item|
|404|Error: Item not found|
## Polling for task status
Now that the task was created, we can retrieve its status by performing a **GET** request on the same endpoint as used for starting task.
Note that the response contains a lot of tasks, and also multiple workflow tasks, indicating that multiple workflows were triggered.
**Request**
```http
GET /api/v1/items/98a480ad8d7444a8a10ef547cd8594eb/tasks HTTP/1.1
Accept: application/json
Authorization: Bearer <access token>
Cache-Control: no-cache
Host: farmmaps.awacc.nl
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
```
**Response**
```http
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Sat, 25 Apr 2020 14:34:01 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-store,no-cache
Pragma: no-cache
Content-Encoding: br
Vary: Accept-Encoding
[
{
"taskType":"vnd.farmmaps.task.workflow",
"code":"52173fb5bf1146efa276ecfe1fda5f60",
"state":1,
"started":"2020-04-25T13:55:28.58133",
"finished":"2020-04-25T13:55:28.750055"
},
{
"taskType":"vnd.farmmaps.task.vandersat",
"code":"0586f0f867014d55a90bfe6adf7416d5",
"state":1,
"started":"2020-04-25T14:00:36.221527",
"finished":"2020-04-25T14:02:18.314088"
},
{ "taskType":"vnd.farmmaps.task.watbal",
"code":"f33cfaff01644313b8de73dcfd42bc20",
"state":3,
"started":"2020-04-25T14:10:46.201482"
},
{
"taskType":"vnd.farmmaps.task.workflow",
"code":"2b76caf17f6d4f5eb497f7ba7609a08c",
"state":1,
"started":"2020-04-25T13:55:41.278677",
"finished":"2020-04-25T13:55:41.442544"
},
{
"taskType":"vnd.farmmaps.task.crprec",
"code":"0ddd635c244c47b8a182aa5f8dddb5db",
"state":1,
"started":"2020-04-25T13:55:33.609931",
"finished":"2020-04-25T13:55:34.464812"
},
{
"taskType":"vnd.farmmaps.task.bofek",
"code":"e95910401dd8493d8483ebde56f8814c",
"state":1,
"started":"2020-04-25T13:55:33.135703",
"finished":"2020-04-25T13:55:34.620735"
},
{
"taskType":"vnd.farmmaps.task.tipstar",
"code":"172f42ece9004013aaf2b6a56b716e39",
"state":1,
"started":"2020-04-25T13:55:33.903717",
"finished":"2020-04-25T13:55:34.636575"
},
{
"taskType":"vnd.farmmaps.task.soilcompaction",
"code":"1667fce90d954b1b90d9997e5e642e8d",
"state":1,
"started":"2020-04-25T13:55:33.575171",
"finished":"2020-04-25T13:55:34.767101"
},
{
"taskType":"vnd.farmmaps.task.ahn",
"code":"23b1e66325134e8cbd778d57865590f2",
"state":1,
"started":"2020-04-25T13:55:33.465586",
"finished":"2020-04-25T13:55:35.170389"
},
{
"taskType":"vnd.farmmaps.task.tipstar",
"code":"80bcf30893614ad288fe8409cee5f9b1",
"state":1,
"started":"2020-04-25T13:55:36.893606",
"finished":"2020-04-25T13:55:37.331862"
},
{
"taskType":"vnd.farmmaps.task.workflow",
"code":"c4c7d23b6e534a7e9b5dfb79847ea449",
"state":1,
"started":"2020-04-25T13:55:37.237456",
"finished":"2020-04-25T13:55:37.567148"
},
{
"taskType":"vnd.farmmaps.task.trijntje",
"code":"e29539ed7a014dfcb739ad3d87298cc2",
"state":1,
"started":"2020-04-25T13:55:44.271105",
"finished":"2020-04-25T13:55:45.64174"
},
{
"taskType":"vnd.farmmaps.task.satellite",
"code":"b5a549be975e4196972806157ee7f2cd",
"state":1,
"started":"2020-04-25T13:55:33.778997",
"finished":"2020-04-25T13:57:13.811563"
},
{
"taskType":"vnd.farmmaps.task.shadow",
"code":"a1daf49cf08142c289825def78986027",
"state":1,
"started":"2020-04-25T13:55:33.153348",
"finished":"2020-04-25T13:56:14.590014"
}
]
```
**Troubleshooting**
|Status code|Description|
|---|---|
|401|Error: Not authenticated|
|403|Error: No READ permissions in parent item|
|404|Error: Parent item not found|
### Polling a single task
Polling for a siingle task can be done by appending g the `ItemTaskCode` to the task URL:
**Request**
```http
GET /api/v1/items/98a480ad8d7444a8a10ef547cd8594eb/tasks/a1daf49cf08142c289825def78986027 HTTP/1.1
Accept: application/json
Authorization: Bearer <access token>
Cache-Control: no-cache
Host: farmmaps.awacc.nl
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
```
**Response**
```http
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Sat, 25 Apr 2020 15:02:05 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-store,no-cache
Pragma: no-cache
Content-Encoding: br
Vary: Accept-Encoding
{
"taskType":"vnd.farmmaps.task.shadow",
"code":"a1daf49cf08142c289825def78986027",
"state":1,
"started":"2020-04-25T13:55:33.153348",
"finished":"2020-04-25T13:56:14.590014"
}
```
**Troubleshooting**
| Status code | Description |
| --- | --- |
| 401 | Error: Not authenticated |
| 403 | Error: No READ permissions in parent item |
| 404 | Error: Parent item not found |
## What's next?
Now that you know how to run a task, you can start running specialized tasks to create or process your own data.
Head over to the [Task Examples](/src/branch/master/Home#task-examples)

117
Upload-Data.md 100644
View File

@ -0,0 +1,117 @@
## Upload Data
If the user wants to upload custom data (lutum/ec) they can use the FarmMaps file API.
The API is based on the google drive API.
C# explanation:
https://developers.google.com/api-client-library/dotnet/guide/media_upload
https://developers.google.com/drive/api/v3/manage-uploads#resumable
* Start request
> Request
```javascript
POST https://farmmaps.awacc.nl/api/v1/file
Host: farmmaps.awtest.nl
Authorization: Bearer < Token >
X-Upload-Content-Length: 13507747
X-Upload-Content-Type: application/x-zip-compressed
Content-Type: application/json; charset=UTF-8
Content-Length: 181
{
"name":"Grondsoorten2006-SHP.zip",
"mimeType":"application/x-zip-compressed",
"size":13507747,
"lastModified":1575293019617,
"parentCode":"c0787987a3f7449c97eecd6d015eb4c2:USER_FILES"
}
```
> Response
```javascript
Location: /api/v1/file/2831cd05ddc0415784930059c658db55
Content-Length: 194
Content-Type: application/json; charset=utf-8
{
"code":"2831cd05ddc0415784930059c658db55",
"chunks":1,
"parentCode":"c0787987a3f7449c97eecd6d015eb4c2:USER_FILES",
"name":"Grondsoorten2006-SHP.zip",
"size":13507747,
"chunkSize":13507747,
"data":{}
}
```
* Request upload chunk 1
> Request
```javascript
PUT https://farmmaps.awtest.nl/api/v1/file/2831cd05ddc0415784930059c658db55
Host: farmmaps.awtest.nl
Authorization: Bearer < Token >
Content-Type: application/octet-stream
Content-Length: 2097152
Content-Range: bytes 0-2097151/13507747
<data>
```
> Response
```javascript
HTTP/1.1 308 Resume Incomplete
Range: 0-2097151
Content-Length: 17
Resume Incomplete
```
* Request upload chunk 2
> Request
```javascript
PUT https://farmmaps.awtest.nl/api/v1/file/2831cd05ddc0415784930059c658db55
Host: farmmaps.awtest.nl
Authorization: Bearer < Token >
Content-Type: application/octet-stream
Content-Length: 2097152
Content-Range: bytes 2097152-4194303/13507747
<data>
```
> Response
```javascript
HTTP/1.1 308 Resume Incomplete
Range: 0-4194303
Content-Length: 17
Resume Incomplete
```
* Final request
> Request
```javascript
PUT https://farmmaps.awtest.nl/api/v1/file/2831cd05ddc0415784930059c658db55
Host: farmmaps.awtest.nl
Authorization: Bearer < Token >
Content-Type: application/octet-stream
Content-Length: 924835
Content-Range: bytes 12582912-13507746/13507747
<data>
```
> Response
```javascript
Upload response laatste chunk
HTTP/1.1 201 Created
Range: 0-13507746
Content-Length: 0
```

235
Upload-a-file.md 100644
View File

@ -0,0 +1,235 @@
# Uploading a file
This page documents how to upload a file through the FarmMaps API.
The FarmMaps file upload API follows the [Google Drive API](https://developers.google.com/drive/api/v3/manage-uploads#resumable) loosely.
Files smaller than 2 MB are uploaded in a single part, larger files need to be split into parts of 1 MB.
The workflow for uploading a file is as follows:
* Register the file for upload.
* Uploading the file chunks
* Downloading the file to check (optional)
**Prerequisites**
- To be able to perform requests, make sure you have an [access token](/src/branch/master/Create-access-token).
### Registering the upload
Before a file can be uploaded it needs to be registered. Files smaller than 2 MB can be uploaded in one chunk.
Bigger files need to be uploaded in chunks of 1 MB. The uploaded files are structured in a hierarchy, so we'll specify a `parentCode` to identify its parent.
We'll first retrieve this parentcode using a GET request to the "my_drive" (root)folder.
**Request**
Replace `<acces token>` with your actual token.
```http
GET https://farmmaps.awacc.nl/api/v1/folders/my_drive? HTTP/1.1
Host: farmmaps.awacc.nl
Accept: application/json
Authorization: Bearer <access token>
```
**Response**
The response will be something similar to:
```http
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Tue, 21 Apr 2020 09:57:07 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-store,no-cache
Pragma: no-cache
Content-Encoding: br
Vary: Accept-Encoding
{
"url":"/api/v1/folders/f25d8765a1cd407cb235961c73c268cf:USER_FILES",
"code":"f25d8765a1cd407cb235961c73c268cf:USER_FILES",
"name":"My Drive",
"created":"2019-09-25T19:39:33.841835",
"updated":"2019-09-25T19:39:33.841835",
"itemType":"ROOT_FOLDER",
"size":0,
"state":0,
"thumbnail":false
}
```
So the `parentcode` we need is **"f25d8765a1cd407cb235961c73c268cf:USER_FILES"**
We can now register the file. In the request to register the upload, we specify its parent (`parentCode`),
the filename (`name`), and the size in bytes (`size`) in the body.
**Request**
```http
POST /api/v1/file HTTP/1.1
Accept: application/json
Authorization: Bearer <access token>
Content-Type: application/json
Cache-Control: no-cache
Host: farmmaps.awacc.nl
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 115
{
"parentCode": "f25d8765a1cd407cb235961c73c268cf:USER_FILES",
"name": "example.csv",
"size": 67351
}
```
**Response**
If all went well, we should recieve a response with status code 201, indicating that a new file was registered.
```http
HTTP/1.1 201 Created
Server: nginx/1.14.0 (Ubuntu)
Date: Tue, 21 Apr 2020 10:08:56 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-store,no-cache
Pragma: no-cache
Content-Encoding: br
Location: /api/v1/file/147357a252044a098788492729c4d551
Vary: Accept-Encoding
{
"code":"147357a252044a098788492729c4d551",
"chunks":1,
"parentCode":"f25d8765a1cd407cb235961c73c268cf:USER_FILES",
"name":"example.csv",
"size":67351,
"chunkSize":67351,
"data":{}
}
```
For files larger than 2 MB we also need to specify the chunksize (`chunkSize`):
```http
POST /api/v1/file HTTP/1.1
Accept: application/json
Authorization: Bearer <access token>
Content-Type: application/json
Cache-Control: no-cache
Host: farmmaps.awacc.nl
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 147
{
"parentCode": "f25d8765a1cd407cb235961c73c268cf:USER_FILES",
"name": "sampledata2.csv",
"size": 7265743,
"chunkSize": 1048576
}
```
**Response**
The response now shows the amount of chunks that we'll need to send ("chunks":7).
```http
HTTP/1.1 201 Created
Server: nginx/1.14.0 (Ubuntu)
Date: Tue, 21 Apr 2020 14:27:05 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-store,no-cache
Pragma: no-cache
Content-Encoding: br
Location: /api/v1/file/f319e9c6bfe3493cba1a888f6292f00a
Vary: Accept-Encoding
{
"code":"f319e9c6bfe3493cba1a888f6292f00a",
"chunks":7,
"parentCode":"f25d8765a1cd407cb235961c73c268cf:USER_FILES",
"name":"sampledata2.csv",
"size":7265743,
"chunkSize":1048576,
"data":{}
}
```
### Uploading the chunks
The upload URL contains the registration code, and ends with the chunk number.
The body of the request contains the data of the chunk. For uploading the first chunk, we can use the request below.
Subsequent chunks can be uploaded by increading the chunk number at the end and adding the next chunk in the body.
**Request**
```http
POST /api/v1/file/9c27d92fd44e43cf975275a2bec5c5f5/chunk/1 HTTP/1.1
Accept: application/json
Authorization: Bearer <access token>
Cache-Control: no-cache
Host: farmmaps.awacc.nl
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: multipart/form-data; boundary=--------------------------272838473781934324854095
Content-Length: 1048788
----------------------------272838473781934324854095
Content-Disposition: form-data; name="Chunk"; filename="sampledata2_1.csv"
<sampledata2_1.csv>
----------------------------272838473781934324854095--
```
**Response**
The response should show a 200 status code, confirming that the chunk was recieved succesfully:
```http
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Tue, 21 Apr 2020 15:07:19 GMT
Content-Length: 0
Connection: keep-alive
Cache-Control: no-store,no-cache
Pragma: no-cache
```
When uploading the final chunk of the file a 201 status code should be returned.
This indicates all chunks have been uploaded. The file will now be ready for further processing.
```http
HTTP/1.1 201 Created
Server: nginx/1.14.0 (Ubuntu)
Date: Tue, 21 Apr 2020 15:21:01 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-store,no-cache
Pragma: no-cache
Content-Encoding: br
Location: /api/v1/item/9c27d92fd44e43cf975275a2bec5c5f5
Vary: Accept-Encoding
```
### Downloading the uploaded file
To verify that your file was uploaded and re-assembled correctly you can download the file using a simple GET request.
```http
GET /api/v1/items/9c27d92fd44e43cf975275a2bec5c5f5/data HTTP/1.1
Accept: application/json
Authorization: Bearer <acces token>
Cache-Control: no-cache
Host: farmmaps.awacc.nl
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
```
This will return the file as an attachment:
```http
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Tue, 21 Apr 2020 16:05:25 GMT
Content-Type: application/octet-stream
Content-Length: 0
Connection: keep-alive
Cache-Control: no-store,no-cache
Pragma: no-cache
Content-Disposition: attachment; filename=sampledata2.csv; filename*=UTF-8''sampledata2.csv
```
**Troubleshooting**
|Status code|Description|
|---|---|
|200|Chunk was uploaded|
|201|All chunks from file have been uploaded|
|400|Error: the chunk number exceeds the total number of chunks calculated earlier|
|401|Error: not authenticated|
|404|Error: the chunk cannot be added to a registered file (not found)|

172
VRAHerbicide-API.md 100644
View File

@ -0,0 +1,172 @@
## VRAHerbicide API
[<< Home](/src/branch/master/Home)
FarmMaps is an asynchronous architecture, the API flow keeps this in mind.
The API expects that all data is already processed and available provided, for example through the normal FarmMaps flow (frontend).
For the currently available public FarmMaps API you can take a look at swagger: http://farmmaps.awtest.nl/swagger/index.html
**Input preperation**
* Users can upload their own data if needed. (in case of when FarmMaps has not processed the required data).
* The farmmaps file API can be used for this.
**Users can poll the task api to see if a task is completed**
**This can be achieved with the task execution id obtained from calling the 'ItemTask' API.**
[Poll task status](/src/branch/master/Polling-task-status)
**Users can query the API for child items of a cropfield to see what items it has.**
### API flow
* Authenticate User
* Optional steps
* *Create cropfield through FarmMaps API*
* Item 'vnd.farmmaps.itemtype.cropfield' must be created with its data as specified in the api.
* Task 'vnd.farmmaps.task.workflow' needs to be executed to aggregate all needed data.
* This is an asynchronous process and can take a while before all data is collected in FarmMaps.
* *Upload own data*
* IF shape data, convert to geotiff.
* Task 'vnd.farmmaps.task.vraherbicide' must be executed to create an application map.
* Task 'vnd.farmmaps.task.taskmap' can be executed to create a taskmap.
* Download item data (tiff of shape)
### Steps
[Authentication](/src/branch/master/Authentication)
##### Optional
[Create Cropfield](/src/branch/master/Create-Cropfield)
[Upload Data](/src/branch/master/Upload-Data)
###### Transform shape to geotiff
The VRAHerbicide task only processes tiff items as input.
If your input data is a processed shape file it first needs to be converted to geotiff, this can be done with the 'ShapeToGeoTiffTask'.
Pass the code of the shape item into the {code} parameter, this creates a new item with tiff data as the parent of the shape item.
This new geotiff item should be used as input to the a task.
> Request
```javascript
POST /api/v1/items/{code}/tasks
{
"taskType": "vnd.farmmaps.task.shapetogeotiff"
}
```
> Response 201
```javascript
{
"code": "string",
"taskType": "vnd.farmmaps.task.shapetogeotiff"
}
```
Response 400 Tasktype not found
Response 401 Not authenticated
Response 403 No WRITE permissions in item
Response 404 Item not found
###### Querying predefined herbicide agents.
A list of herbicide agents can be requested by finding the "vnd.farmmaps.package.vra.herbicide" items, taking the first item found and reading it's data field 'agents' array content.
> Request
```javascript
GET /api/v1/items/?it=vnd.farmmaps.package.vra.herbicide
```
> Response 201
```javascript
{
"code": "....",
"data": {
"agents": [
{
"name": "Liberator",
"SoilType": "Dalgrond",
"ExtraInputType": "Lutum",
"MinDosis": 2,
"MaxDosis": 3,
"A": 0.1428,
"B": 1.285714,
"C": 1,
"D": 97,
"E": 3,
"P": 1,
"Crop": "Zetmeelaardappelen"
}
]
}
}
```
Response 400 Tasktype not found
Response 401 Not authenticated
Response 403 No READ permissions in item
Response 404 Items not found
###### Creating an application map with the VRAHerbicide task
Execute the task with the item code of the cropfield as parameter inside {code}.
Use the input map code inside {itemCode}, specifying an inputCode for the input data item.
{itemCode} needs the code of the data input item passed into it.
An **optional** {extraItemCode} can be passed inside the 'extraInputcode' field to process herbicide from 2 inputs.
Fill in the agent field with an agent gotten from the herbicide agents query discussed above.
The resulting application map will be created as a child item of the cropfield item (this can be queried).
> Request
```javascript
POST /api/v1/items/{code}/tasks
{
"taskType": "vnd.farmmaps.task.vraherbicide",
"attributes": {
"inputCode": "{itemCode}",
"extraInputCode": "{extraItemCode}",
"agent": {
"SoilType": "Dalgrond",
"ExtraInputType": "Lutum",
"MinDosis": 2,
"MaxDosis": 3,
"A": 0.1428,
"B": 1.285714,
"C": 1,
"D": 97,
"E": 3,
"P": 1,
"Crop": "Zetmeelaardappelen"
}
}
}
```
> Response 201
```javascript
{
"code": "string", // code of task operation, can be queried for status
"taskType": "vnd.farmmaps.task.vraherbicide",
"attributes": {
"inputCode": "{itemCode}",
"extraInputCode": "{extraItemCode}",
"agent": {
"SoilType": "Dalgrond",
"ExtraInputType": "Lutum",
"MinDosis": 2,
"MaxDosis": 3,
"A": 0.1428,
"B": 1.285714,
"C": 1,
"D": 97,
"E": 3,
"P": 1,
"Crop": "Zetmeelaardappelen"
}
}
}
```
Response 400 Tasktype not found
Response 401 Not authenticated
Response 403 No WRITE permissions in item
Response 404 Item not found
##### Create taskmap
[Create Taskmap](/src/branch/master/Create-Taskmap)
##### Download the data
In case the data is available it can be downloaded with the File API.
> Request
```javascript
GET /api/v1/items/{itemcode}/data

295
VRANbs-API.md 100644
View File

@ -0,0 +1,295 @@
## VRANbs API v0.2
[<< Home](/src/branch/master/Home)
FarmMaps is an asynchronous architecture, the API flow keeps this in mind.
The API expects that all data is already processed and available provided, for example through the normal FarmMaps flow (frontend).
For the currently available public FarmMaps API you can take a look at swagger: http://farmmaps.awtest.nl/swagger/index.html
**Limitations**
* Currently VRANbs only accepts input tiffs in WGS84/EPSG4326
* Data isn't automatically deleted as farmmaps has no support for this.
* But API users can delete their own items through the farmmaps API.
**Input preperation**
* Users can upload their own data if needed. (in case of when FarmMaps has not processed the required data).
* The farmmaps file API can be used for this.
**Users can poll the task api to see if a task is completed**
**This can be achieved with the task execution id obtained from calling the 'ItemTask' API.**
[Poll task status](/src/branch/master/Polling-task-status)
**Users can query the API for child items of a cropfield to see what items it has.**
### API flow
* Authenticate User
* Optional steps
* *Create cropfield through FarmMaps API*
* Item 'vnd.farmmaps.itemtype.cropfield' must be created with its data as specified in the api.
* Task 'vnd.farmmaps.task.workflow' needs to be executed to aggregate all needed data.
* This is an asynchronous process and can take a while before all data is collected in FarmMaps.
* *Upload own data*
* IF shape data, convert to geotiff.
* *Create 'vnd.farmmaps.itemtype.user.input' item for targetn calculation.*
* *Task 'vnd.farmmaps.task.vranbs' can be executed with the 'targetn' operation*
* *Task 'vnd.farmmaps.task.vranbs' can be executed with 'uptake' operation* to create an nitrogen uptake map.
* Task 'vnd.farmmaps.task.vranbs' must be executed with 'nitrogen' operation to create an appliance map.
* Task 'vnd.farmmaps.task.taskmap' can be executed to create a taskmap.
* Download item data (tiff of shape)
### Steps
[Authentication](/src/branch/master/Authentication)
##### Optional
[Create Cropfield](/src/branch/master/Create-Cropfield)
[Upload Data](/src/branch/master/Upload-Data)
###### Transform shape to geotiff
The VRANbs task only processes tiff items as input.
If your input data is a processed shape file it first needs to be converted to geotiff, this can be done with the 'ShapeToGeoTiffTask'.
Pass the code of the shape item into the {code} parameter, this creates a new item with tiff data as the parent of the shape item.
This new geotiff item should be used as input to the vranbs task.
> Request
```javascript
POST /api/v1/items/{code}/tasks
{
"taskType": "vnd.farmmaps.task.shapetogeotiff"
}
```
> Response 201
```javascript
{
"code": "string",
"taskType": "vnd.farmmaps.task.shapetogeotiff"
}
```
Response 400 Tasktype not found
Response 401 Not authenticated
Response 403 No WRITE permissions in item
Response 404 Item not found
##### Using VRA Nitrogen fertilization task
The VraNbs task currently supports 3 operations:
* **targetn** - calculates the target nitrogen based on target yield.
* **uptake** - creates the nitrogen uptake map.
* **application** - creates the nitrogen fertilization application map.
###### targetn operation
Create a 'vnd.farmmaps.itemtype.user.input' item to use in this operation.
(step not needed if you already know the target nitrogen you want to work with.)
The user.input item must parent the '{user_code}:USER_IN' item and can be obtained by calling following request:
> Request
```javascript
GET /api/v1/Folders/my_uploads
```
> Response 201
```javascript
{
"url": "/api/v1/folders/{user_code}:USER_IN",
"code": "{user_code}:USER_IN",
"name": "Uploaded",
"created": "2020-03-04T14:41:41.099557",
"updated": "2020-03-04T14:41:41.099557",
"itemType": "FOLDER",
"size": 0,
"state": 0,
"thumbnail": false
}
```
**Create item**
Create user.input item, pass just obtained parent code as parameter in {user_code}.
> Request
```javascript
POST /api/v1/items
{
"parentCode": "{user_code}:USER_IN",
"itemType": "vnd.farmmaps.itemtype.user.input",
"name": "TargetN",
"dataDate": "2020-03-02T14:22:09.265Z"
}
```
> Response 201 Created
```javascript
{
"parentCode": "string",
"geometry": {},
"data": {},
"tags": [
"string"
],
"url": "string",
"code": "string",
"name": "string",
"created": "2019-12-18T10:16:21.455Z",
"updated": "2019-12-18T10:16:21.455Z",
"dataDate": "2019-12-18T10:16:21.455Z",
"itemType": "string",
"sourceTask": "string",
"size": 0,
"state": 0,
"thumbnail": true
}
```
Response 401 Not authenticated
Response 403 No WRITE permissions in parent item
Response 404 Parent Item not found
**Call the vranbs task**
Execute the VRANbsTask with the item code of the cropfield as parameter inside {code}.
Use the code obtained from creating the user.input item as a parameter in {itemCode}.
> Request
```javascript
POST /api/v1/items/{code}/tasks
{
"taskType": "vnd.farmmaps.task.vranbs",
"attributes": {
"operation": "targetn",
"inputCode": "{itemCode}",
"plantingDate": "2020-02-01T00:00:00.000Z",
"measurementDate": "2020-06-01T00:00:00.000Z",
"purposeType": "consumption", // consumption, fries, potato, starch
"targetYield": "60"
}
}
```
> Response 201
```javascript
{
"code": "string",
"taskType": "vnd.farmmaps.task.workflow"
}
```
Response 400 Tasktype not found
Response 401 Not authenticated
Response 403 No WRITE permissions in item
Response 404 Item not found
**Query user.input targetN item**
You can query the user.input item to get the calculated targetN value from the data field of the item.
> Request
```javascript
GET /api/v1/items/{code}
```
> Response 200
```javascript
{
"parentCode": "string",
"geometry": {},
"data": {
"TSum": "2700",
"TargetYield": "60",
"TargetN": "249.2341"
},
"tags": [
"string"
],
"url": "string",
"code": "string",
"name": "TargetN",
"created": "2019-12-18T10:16:21.455Z",
"updated": "2019-12-18T10:16:21.455Z",
"dataDate": "2019-12-18T10:16:21.455Z",
"itemType": "vnd.farmmaps.itemtype.user.input",
"sourceTask": "string",
"size": 0,
"state": 0,
"thumbnail": true
}
```
###### Uptake map operation
Execute the VRANbsTask with the item code of the cropfield as parameter inside {code}.
Use the input map code inside {itemCode}, specifying an inputCode for the input data item.
{itemCode} needs the code of the data input item passed into it. ex. uploaded isaria/data data.
The resulting nitrogen uptake map will be created as a child item under the cropfield item (this can be queried).
> Request
```javascript
POST /api/v1/items/{code}/tasks
{
"taskType": "vnd.farmmaps.task.vranbs",
"attributes": {
"operation": "uptake",
"inputCode": "{itemCode}",
"plantingDate": "2020-02-01T00:00:00.000Z",
"measurementDate": "2020-06-01T00:00:00.000Z",
"inputType": "irmi", // yara, ci, irmi or wdvi
}
}
```
> Response 201
```javascript
{
"code": "string", // code of task operation, can be queried for status
"taskType": "vnd.farmmaps.task.vranbs",
"attributes": {
"operation": "uptake",
"inputCode": "{itemCode}",
"inputType": "irmi", // yara, ci, irmi or wdvi
}
}
```
Response 400 Tasktype not found
Response 401 Not authenticated
Response 403 No WRITE permissions in item
Response 404 Item not found
###### Application map operation
Execute the VRANbsTask with the item code of the cropfield as parameter inside {code}.
Use the input map code inside {itemCode}, specifying an inputCode for the input data item.
{itemCode} needs the code of the data input item passed into it. ex. uploaded isaria/data data.
The resulting nitrogen application map will be created as a child item under the cropfield item (this can be queried).
> Request
```javascript
POST /api/v1/items/{code}/tasks
{
"taskType": "vnd.farmmaps.task.vranbs",
"attributes": {
"operation": "application",
"inputCode": "{itemCode}",
"plantingDate": "2020-02-01T00:00:00.000Z",
"measurementDate": "2020-06-01T00:00:00.000Z",
"inputType": "irmi", // yara, ci, irmi or wdvi
"targetN": "249.22948"
}
}
```
> Response 201
```javascript
{
"code": "string", // code of task operation, can be queried for status
"taskType": "vnd.farmmaps.task.vranbs",
"attributes": {
"operation": "nitrogen",
"inputCode": "{itemCode}",
"inputType": "irmi", // yara, ci, irmi or wdvi
"targetN": "249.22948"
}
}
```
Response 400 Tasktype not found
Response 401 Not authenticated
Response 403 No WRITE permissions in item
Response 404 Item not found
##### Create taskmap
[Create Taskmap](/src/branch/master/Create-Taskmap)
##### Download the data
In case the data is available it can be downloaded with the File API.
> Request
```javascript
GET /api/v1/items/{itemcode}/data

85
VRAPoten-API.md 100644
View File

@ -0,0 +1,85 @@
## VRAPoten API v0.1.1
[<< Home](/src/branch/master/Home)
FarmMaps is an asynchronous architecture, the API flow keeps this in mind.
The API expects that all data is already processed and available provided, for example through the normal FarmMaps flow.
For the currently available public FarmMaps API you can take a look at swagger: http://farmmaps.awtest.nl/swagger/index.html
**Input preperation**
* VRAPoten requires specific input which needs to be provided by the FarmMaps API or user interface.
* You can activate the VRAPotenTask with the Task API, passing the just created cropfield item code as a parameter.
* Users can upload their own soilmaps if needed. (in case of when FarmMaps has not processed the required data).
* The file API can be used for this.
**Users can poll the task api to see if a task is completed**
**This can be achieved with the task execution id obtained from calling the 'ItemTask' API.**
[Poll task status](/src/branch/master/Polling-task-status)
### API flow
* Authenticate User
* *Create cropfield through FarmMaps API (optioneel)*
* Item 'FOLDER' must be created for parent to cropfields.
* Item 'vnd.farmmaps.itemtype.cropfield' must be created with its data as specified in the api.
* Task 'vnd.farmmaps.task.workflow' needs to be executed to aggregate all needed data.
* This is an asynchronous process and can take a while before all data is collected in FarmMaps.
* Upload own soil data (optioneel)
* Task 'vnd.farmmaps.task.vrapoten' must be executed to create an appliance map.
* Task 'vnd.farmmaps.task.taskmap' must be executed to create a taskmap.
* Download item data (tiff of shape)
### Steps
###### Authentication
[Authentication](/src/branch/master/Authentication)
###### Create cropfield with FarmMaps API (optional)
[Create Cropfield](/src/branch/master/Create-Cropfield)
###### Uploading own data (optional)
[Upload Data](/src/branch/master/Upload-Data)
###### Creating appliance maps
Execute the VRAPotenTask with the item code of the cropfield as parameter inside {code}.
Use the input map code inside {itemCode}, specifying an inputCode is optional.
In case of no specified inputCode the BOFEK data is looked up and if it could not be found the task gives an error.
> Request
```javascript
POST /api/v1/items/{code}/tasks
{
"taskType": "vnd.farmmaps.task.vrapoten",
"attributes": {
"inputCode": "{itemCode}",
"meanDensity": "30",
"variation": "20"
}
}
```
> Response 201
```javascript
{
"code": "string",
"taskType": "vnd.farmmaps.task.workflow",
"delay": "",
"attributes": {
"additionalProp1": "string",
"additionalProp2": "string",
"additionalProp3": "string"
}
}
```
Response 400 Tasktype not found
Response 401 Not authenticated
Response 403 No WRITE permissions in item
Response 404 Item not found
###### Create taskmap
[Create Taskmap](/src/branch/master/Create-Taskmap)
###### Download the data
In case the data is available it can be downloaded with the File API.
> Request
```javascript
GET /api/v1/items/{itemcode}/data
```

43
Workflow.md 100644
View File

@ -0,0 +1,43 @@
# FarmMaps Workflow
This page explains how FarmMaps processes incoming data so that it can be used in the FarmMaps application, and data becomes easily retrievable through the interface.
Depending on the type of data, the system might process the data differently, how this works is explained below.
## General workflow
As mentioned earlier, the REST API is the primary API endpoint.
The workflow starts with registering a new upload, and uploading the file in chunks.
Once a file has been uploaded succesfully through the REST API, FarmMaps will automatically start to process the file step by step.
In the processing workflow, there are 3 common, not dependent on the type of file.
After the common steps, the workflow starts tasks for the specific type of file.
So, when a file has been uploaded completely, FarmMaps will:
* Start a stitching task to reasemble the chunks back into a single file.
* Start an identification task to identify the type of file, and identify what the next processing step should be.
* Start the file-type specific workflow, starting with the first task defined in the file-type specific workflow.
Each time a task is started, a separate process is created called a worker.
This worker then executes the task and reports back to the main FarmMaps workflow once it has completed.
The main workflow will then start the next task untill all processing steps defined for that specific type of file are completed.
Once the primary processing is completed, the data is available for viewing through the FarmMaps GUI.
Also, other tasks can be started that use the pre-processed data.
These are tasks such as generating a task map, or creating derived datasets from the pre-processed data.
## Stitching task
Because files are uploaded in chunks in FarmMaps, these chunks need to re-assembled into the original file.
This task is started automatically.
## Identification task
Once a file is re-assembled, FarmMaps will try to identify the file.
It does so by looking at the file extension (i.e. `.csv`, `.shp`, `.tif`), the binary structure, and the content structure.
Once it recognizes the type of file that was uploaded, FarmMaps stores this information as metadata in the database, with a reference to the file.
The system can then look up the correct file specific workflow, and related tasks.
### File specific task
Once the file has been identified and the correct file-type specific workflow is known, FarmMaps will start the with the first task listed in that workflow.
It uses the resulting file of the stitching task, and depending on the type of task generally creates a new file with the converted data.
A good example would be a `.csv` file that was uploaded, that would be converted to a `.shp` or shapefile.
Once the data conversion has completed, the database is updated to point to the new file instead of the original `.csv`.
The system does however keep track of the previous version and also keeps this in store, so the same data can easily be retrieved in different formats or versions.
When the next file-specific task starts, this step repeats and another "version" of the same data is created.

1
examples/Home.md 100644
View File

@ -0,0 +1 @@
### Examples