REST-API: create HTML page with file upload

23 views
Skip to first unread message

Sven Schirmer

unread,
Jul 8, 2025, 5:41:50 AMJul 8
to OpenOlat
Hi

I wish to migrate many existing HTML pages into various courses. It works well one by one using the Web UI. However, I wish to do this using the REST-API. I tried with this endpoint: /repo/courses/{courseId}/elements/singlepage using the filename and filepath attributes, but I get a 404 response: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.

Other API requests (like creating a courdsee etc) work well.

Please advice how to create a HTML page within a course and upload a local HTML file.

Many thanks in advance
Best regards
Sven

Stéphane Rossé

unread,
Jul 10, 2025, 2:52:50 AMJul 10
to OpenOlat

Hi

This endpoint only creates new course element of type "Single page". You need to send a PUT or POST request with the MimeType multipart/form-data and encode the file and in the multipart payload you need to add a binary body "file" with the HTML page and some other metadata like "filename", "shortTitle", "longTitle" as text to create the course element.

Best regards
Stéphane

Sven Schirmer

unread,
Jul 15, 2025, 11:00:08 AMJul 15
to OpenOlat
Dear Stéphane

many thanks for your answer. After some more digging in the code and the API, I understand my lack of OpenOlat concepts. 
According to the attach function of AbstractCourseNodeWebService.java (which handles the very API endpoint), an 404 error is raised either if courseId or the parentNodeId is wrong.

If I get for example the courses via API call, they have this format:

<courseVO>
<key>112125159549320</key>
<softKey>myopenolat_1_112125159549321</softKey>
<displayName>Kurs 101</displayName>
<description></description>
<repoEntryKey>720896</repoEntryKey>
<repoEntryStatus>published</repoEntryStatus>
<externalRef></externalRef>
<olatResourceKey>196610</olatResourceKey>
<olatResourceId>112125159549320</olatResourceId>
<olatResourceTypeName>CourseModule</olatResourceTypeName>
<title>Kurs 101</title>
<editorRootNodeId>112125159549322</editorRootNodeId>
<nodeAccessType>learningpath</nodeAccessType>
</courseVO>

Can you please clarify, which of these Ids and Keys is the courseId, and which is the parentNodeid I could use for my API call?
As well, do you know which table in the database contains the actual courses?

Many thanks in advance
Best regards
Sven

Stéphane Rossé

unread,
Jul 16, 2025, 5:54:32 AMJul 16
to OpenOlat
Dear Sven

The courseId is the key in courseVO,  the parentNodeId can be editorRootNodeId.
"editorRootNodeId" is the id of the root course element.

Best regards
Stéphane

Sven Schirmer

unread,
Jul 17, 2025, 4:34:20 AMJul 17
to OpenOlat
Great - it works - many thanks!

Here's a draft how to do this in python (if anyone needs it):

import requests
from dotenv import load_dotenv
import os

# Endpoint URL
url = "http://localhost:8080/OpenOLAT/restapi/repo/courses/{courseId}/elements/singlepage"

path="/home/sven/git/M323-FunProg/sidequests/5b_Lambda_II/5B_aufgabe.html"

load_dotenv()
# Basic auth credentials
username = os.getenv('OLAT_USER')
password = os.getenv('PASSWD')

try :
courseId = 112125159549320
url = url.replace('{courseId}', str(courseId))

data = {
"shortTitle": path.split("/")[-1].split("_")[0],
"longTitle": path.split("/")[-1].split(".")[0],
"filename": path.split("/")[-1],
"parentNodeId": 112125159549322,
}

print(f'Sending request to {url}')
response = requests.put(url,
data=data,
files={'path': (data['filename'] , open(path, 'rb'), "text/html")}, # that tupel was really hard to get...
#headers=..., -- don't use hand-made content-type, python.request does it automatically, incl. correct boundaries
auth=(username, password))

# Print response details
print(f"Status Code: {response.status_code}")

except Exception as e:
print(f"Another error occurred: {e}")

Reply all
Reply to author
Forward
0 new messages