Posting form attachments via ODK Central API

Hello,

Is it possible to post media files via curl to ODK Central?
I am in the process of migrating to Central and my forms rely on media files that are updated daily.

In ONA, the process involves first deleting the old media file and then posting a new one:
curl -X DELETE https://api.ona.io/api/v1/metadata/[MEDIA_ID] -u [USER]:[PASSWORD]
curl -X POST -F 'data_type=media' -F 'data_value=[FILENAME.csv]' -F 'xform=[FORM_ID]' -F 'data_file=@[PATH_TO_FILE.csv]' https://api.ona.io/api/v1/metadata.json -u [USER]:[PASSWORD]

Can I do something analogous for Central?
(My operating system is MacOS 10.15.4. I also use R 4.0.0)

Thank you for any guidance.

Best,
Nicholai

Hi Nicholai! When you get a chance, please introduce yourself here. I'd also encourage you to add a real picture as your avatar because it helps build community.

Central has a fully-featured REST API that works great with curl. That API that is documented at https://odkcentral.docs.apiary.io. There is also link to this documentation at https://docs.getodk.org/central-api. Have you had a chance to look through the API docs?

Hi Yaw,

Thank you for the response.
I introduced myself a while ago... but I guess it was a different user name. I can make another intro in a separate post. I run a solar business in Liberia and our operations rely heavily on ODK.

I apologize for struggling with this -- the API docs are very good! I just can't seem to figure out how to post or delete a form attachment.

For example, I can get a list of form attachments using this:
curl --include
--request GET
--header "Authorization: Basic [BASE64ENCODE]"
'https://WEBSITE.com/v1/projects/2/forms/PaymentsCentral/attachments'

Which returns information on the two existing form attachments, which I loaded manually:
[{"name":"customers.csv","type":"file","exists":true,"updatedAt":"2020-05-12T14:51:12.414Z"},{"name":"payments.csv","type":"file","exists":true,"updatedAt":"2020-05-12T14:51:06.813Z"}]%

But I can't figure out the format to POST an attachment via curl. The attachment is a .csv file on my local disk.

Using the API docs, I get to this point:
curl --include
--request POST
--header "Authorization: Basic [BASE64ENCODE]"
--header "Content-Type: text/csv"
'https://WEBSITE.com/v1/projects/2/forms/PaymentsCentral/attachments/customers.csv'

But I can't find the correct way to link to the local .csv file.
And I'm guessing I need to delete the old attachment before uploading a more recent version?

Again, I'm sorry for the hand-holding. I really appreciate your help.

Best,
Nicholai

I think I'm missing something basic here, so any thoughts are much appreciated.
My goal is to POST an updated form attachment (a csv file) via curl.

I can download the current version of the attachment like this:
curl -X GET -H 'Authorization: Basic [BASE64ENCODE]' 'https://WEBSITE.com/v1/projects/2/forms/PaymentsCentral/attachments/customers.csv'

But when I try something simple, like deleting the attachment, I get an error. E.g.,
curl -X DELETE -H 'Authorization: Basic [BASE64ENCODE]' 'https://WEBSITE.com/v1/projects/2/forms/PaymentsCentral/attachments/customers.csv'

Returns {"message":"Could not find the resource you were looking for.","code":404.1}%

Any attempt to POST a csv file, using either
curl -X POST -H 'Content-Type: text/csv' -d @file.csv ...
or -F ‘data=@<file_location>’ returns a similar error

Thank you,
Nicholai

Success!
Haha, I know I've been talking to myself on here. But I figured out the solution for regularly updating form attachments in Central via API.

The main challenge was that I didn't understand that it's not possible to delete / post to the published form directly.

So the process is:

  1. Post the form again as a draft
  2. Post the attachments to the draft form
  3. Publish the form with a new version number (which can be supplied in the API call, no need to update the version number inside the form.

For those of you, like myself, who need explicit code, here is what worked for me:

  1. Post the .xlsx form as a draft
    curl --include
    --request POST
    --header "Authorization: Basic [BASE64_ENCODE_OF_email:password]"
    --header "Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    --header "X-XlsForm-FormId-Fallback: [FormID]"
    --data-binary "@[FILE_PATH_TO_FORM.xlsx]"
    'https://WEBSITE.com/v1/projects/[ProjectID]/forms/[FormID]/draft?ignoreWarnings=true'

  2. Post attachments to the form
    curl --include
    --request POST
    --header "Authorization: Basic [BASE64_ENCODE_OF_email:password]"
    --header "Content-Type: text/csv"
    --data-binary "@[FILE_PATH_TO_ATTACHMENT.csv]"
    'h ttps://WEBSITE.com/v1/projects/[ProjectID]/forms/[FormID]/draft/attachments/ATTACHMENT.csv'

  3. Publish form with updated version
    curl --include
    --request POST
    --header "Authorization: Basic [BASE64_ENCODE_OF_email:password]"
    'h ttps://WEBSITE.com/v1/projects/[ProjectID]/forms/[FormID]/draft/publish?version=NEW_VERSION'

7 Likes

Is it now possible or soon likely to be possible to simply upload a new media file without having to republish the form