A Spring Boot back-end for Code Browser (Java 7 + Java EE 7 + Spring Boot 1.1.7.RELEASE).
Start the server with mvn spring-boot:run
.
Run tests with mvn test
.
Build the project with mvn package
.
You need to configure a few properties to get the API running — mainly setting the credentials for the TMC Snapshot API, Test My Code API user credentials and the credentials for the service itself.
- For development purposes create a configuration-file
src/main/resources/application-development.properties
. See a sample configuration insrc/main/resources/application-development.properties.sample
. - Modify the properties to set the credentials and connection information for the service,
tmc-snapshot-api
andtmc-server
.
- Modify the active profile
spring.profiles.active
toproduction
insrc/main/resources/application.properties
. - Create a configuration-file
src/main/resources/application-production.properties
for the production-profile. See a sample configuration insrc/main/resources/application-development.properties.sample
. - Modify the properties to set the credentials and connection information for the service,
tmc-snapshot-api
andtmc-server
.
You can also set additional properties as declared in the .properties
-files.
The REST API provides mostly JSON-responses as application/json
. Files are returned as text/plain
or application/zip
. The API uses basic access for authentication. A successfully authenticated request returns a token in the X-Authentication-Token
-header. This token can be used as an access token, eliminating the need to pass a username and password on all requests. An access token behaves as a password for an empty username with Basic authentication.
All IDs in the API are specified as strings. The ID for an instance is its name. The ID for a student is a URL-safe Base64-encoded string from a username, which matches to the username specified in TMC. The ID for a course and exercise is a URL-safe Base64-encoded string from a course and exercise name, which also match to their corresponding names in TMC. The ID for a snapshot is a string concatenated from the timestamp and nanotime for the snapshot. The ID for a file is a URL-safe Base64-encoded string concatenated from a file path, snapshot timestamp and nanotime.
There are two levels for snapshots. Key-level snapshots — which is the default — provide snapshots that progress one keystroke (or event) at a time. This provides a way to “playback” the snapshots, the same way as a student has implemented the solution. Code-level snapshots provide snapshots that have a larger scope. These snapshots are “full snapshots” that are collected for example when the user saves the solution.
Method: GET
Content-Type: application/json
URL: /
Returns: A list of instances
GET /
[
{
"id": "hy",
"name": "hy"
},
{
"id": "mooc",
"name": "mooc"
}
]
Method: GET
Content-Type: application/json
URL: /{instanceId}/
Returns: A single instance matching the provided ID
GET /hy/
{
"id": "hy",
"name": "hy"
}
Method: GET
Content-Type: application/json
URL: /{instanceId}/students/
Returns: A list of students for the requested instance
GET /hy/students/
[
{
"id": "dXNlcjE",
"username": "user1",
"name": "User Usersson"
},
{
"id": "ZXhhbXBsZQ",
"username": "example",
"name": "Ex Ample"
}
]
Method: GET
Content-Type: application/json
URL: /{instanceId}/courses/{courseId}/exercises/{exerciseId}/students/
Returns: All students for the specified instance’s specified course’s specified exercise
GET /hy/courses/czIwMTQtdGlyYQ/exercises/dmlpa2tvMDEtdGlyYTEuMQ/students/
[
{
"id": "dXNlcjE",
"username": "user1",
"name": "User Usersson"
},
{
"id": "ZXhhbXBsZQ",
"username": "example",
"name": "Ex Ample"
}
]
Method: GET
Content-Type: application/json
URL: /{instanceId}/students/{studentId}/
Returns: A single student for the specified instance
GET /hy/students/dXNlcjE/
{
"id": "dXNlcjE",
"username": "user1",
"name": "User Usersson"
}
Method: GET
Content-Type: application/json
URL: /{instanceId}/courses/{courseId}/exercises/{exerciseId}/students/{studentId}/
Returns: A single student for the specified instance’s specified course’s specified exercise
GET /hy/courses/czIwMTQtdGlyYQ/exercises/dmlpa2tvMDEtdGlyYTEuMQ/students/dXNlcjE/
{
"id": "dXNlcjE",
"username": "user1",
"name": "User Usersson"
}
Method: GET
Content-Type: application/json
URL: /{instanceId}/courses/
Returns: A list of all the courses for the specified instance
GET /hy/courses/
[
{
"id": "azIwMTQtb2hqYQ",
"name": "k2014-ohja",
"exercises": []
},
{
"id": "azIwMTQtb2hwZQ",
"name": "k2014-ohpe",
"exercises": []
}
]
Method: GET
Content-Type: application/json
URL: /{instanceId}/students/{studentId}/courses/
Returns: A single course for the specified instance’s specified student
GET /hy/students/dXNlcjE/courses/
[
{
"id": "czIwMTQtdGlyYQ",
"name": "s2014-tira",
"exercises": [
{
"id": "dmlpa2tvMDEtdGlyYTEuMQ",
"name": "viikko01-tira1.1"
},
{
"id": "dmlpa2tvMDEtdGlyYTEuMg",
"name": "viikko01-tira1.2"
}
]
}
]
Method: GET
Content-Type: application/json
URL: /{instanceId}/courses/{courseId}/
Returns: A single course for the speficied instance
GET /hy/courses/czIwMTQtdGlyYQ/
{
"id": "czIwMTQtdGlyYQ",
"name": "s2014-tira",
"exercises": [
{
"id": "dmlpa2tvMDEtdGlyYTEuMQ",
"name": "viikko01-tira1.1"
},
{
"id": "dmlpa2tvMDEtdGlyYTEuMg",
"name": "viikko01-tira1.2"
}
]
}
Method: GET
Content-Type: application/json
URL: /{instanceId}/students/{studentId}/courses/{courseId}/
Returns: A single course for the specified instance’s specified student
GET /hy/students/dXNlcjE/courses/czIwMTQtdGlyYQ/
{
"id": "czIwMTQtdGlyYQ",
"name": "s2014-tira",
"exercises": [
{
"id": "dmlpa2tvMDEtdGlyYTEuMQ",
"name": "viikko01-tira1.1"
}
]
}
Method: GET
Content-Type: application/json
URL: /{instanceId}/courses/{courseId}/exercises/
Returns: A list of exercises for the requested instance’s requested course.
GET /hy/courses/azIwMTQtb2hqYQ/exercises/
[
{
"id": "dmlpa2tvNy1WaWlra283XzEwOS5IeW1pb3Q",
"name": "viikko7-Viikko7_109.Hymiot"
},
{
"id": "dmlpa2tvNy1WaWlra283XzExMC5NZXJra2lqb25vbXV1bnRhamE",
"name": "viikko7-Viikko7_110.Merkkijonomuuntaja"
}
]
Method: GET
Content-Type: application/json
URL: /{instanceId}/students/{studentId}/courses/{courseId}/exercises/
Returns: A list of exercises for the requested instance’s requested student’s requested course
GET /hy/students/dXNlcjE/courses/czIwMTQtdGlyYQ/exercises/
[
{
"id": "dmlpa2tvMDEtdGlyYTEuMQ",
"name": "viikko01-tira1.1"
},
{
"id": "dmlpa2tvMDEtdGlyYTEuMg",
"name": "viikko01-tira1.2"
}
]
Method: GET
Content-Type: application/json
URL: /{instanceId}/courses/{courseId}/exercises/{exerciseId}/
Returns: A single exercise matching the provided ID for the requested instance’s requested course
GET /hy/courses/azIwMTQtb2hqYQ/exercises/dmlpa2tvNy1WaWlra283XzEwOS5IeW1pb3Q/
{
"id": "dmlpa2tvNy1WaWlra283XzEwOS5IeW1pb3Q",
"name": "viikko7-Viikko7_109.Hymiot"
}
Method: GET
Content-Type: application/json
URL: /{instanceId}/students/{studentId}/courses/{courseId}/exercises/{exerciseId}/
Returns: A single exercise matching the provided ID for the requested instance’s requested student’s requested course
GET /hy/students/dXNlcjE/courses/czIwMTQtdGlyYQ/exercises/dmlpa2tvMDEtdGlyYTEuMQ/
{
"id": "dmlpa2tvMDEtdGlyYTEuMQ",
"name": "viikko01-tira1.1"
}
All the URLs in this section work relative to both these two URLs: /{instanceId}/students/{studentId}/courses/{courseId}/exercises/{exerciseId}
and /{instanceId}/courses/{courseId}/exercises/{exerciseId}/students/{studentId}
.
All URLs in this section take an optional parameter key
. Allowed values are key
and code
. Using the level key
returns as fine grained snapshots as possible. This can mean as much as a snapshot for each keypress the user has made. Using the level code
returns only snaphots that are created from full project snapshots. These correspond to higher level events such as saving a file, running tests and so on.
The default value used when no parameter is provided is key
.
Method: GET
Content-Type: application/json
URL: /snapshots/(?level=[key|code])
Returns: A list of all the snapshots relating to the start of the URL
GET /hy/students/dXNlcjE/courses/czIwMTQtdGlyYQ/exercises/dmlpa2tvMDEtdGlyYTEuMQ/snapshots/?level=key
[
{
"id": "140943627771047191388761820",
"timestamp": 1409436277710,
"files": [
{
"id": "c3JjL01haW4uamF2YTE0MDk0MzYyNzc3MTA0NzE5MTM4ODc2MTgyMA",
"name": "Main.java",
"path": "src/Main.java"
}
]
},
{
"id": "140943628816547201843913774",
"timestamp": 1409436288165,
"files": [
{
"id": "c3JjL01haW4uamF2YTE0MDk0MzYyODgxNjU0NzIwMTg0MzkxMzc3NA",
"name": "Main.java",
"path": "src/Main.java"
}
]
}
]
Method: GET
Content-Type: application/json
URL: /snapshots/{snapshotId}(?level=[key|code])
Returns: A single snapshots relating to the start of the URL and the provided ID
GET /hy/students/dXNlcjE/courses/czIwMTQtdGlyYQ/exercises/dmlpa2tvMDEtdGlyYTEuMQ/snapshots/140943628816547201843913774/?level=key
{
"id": "140943627771047191388761820",
"timestamp": 1409436277710,
"files": [
{
"id": "c3JjL01haW4uamF2YTE0MDk0MzYyNzc3MTA0NzE5MTM4ODc2MTgyMA",
"name": "Main.java",
"path": "src/Main.java"
}
]
}
Method: GET
Content-Type: application/zip
URL: /snapshots/files.zip(?level=[key|code])
Parameters: from [snapshotId], optional, files are returned from this snapshot onwards
count [Integer], optional, amount of snapshots to return
Returns: A ZIP containing all the snapshots and and their files relating to the start of the URL
GET /hy/students/dXNlcjE/courses/czIwMTQtdGlyYQ/exercises/dmlpa2tvMDEtdGlyYTEuMQ/snapshots/files.zip
The following is an example of the file structure found in the ZIP:
files
├── 140943627771047191388761820
│ └── c3JjL01haW4uamF2YTE0MDk0MzYyNzc3MTA0NzE5MTM4ODc2MTgyMA
└── 140943628816547201843913774
└── c3JjL01haW4uamF2YTE0MDk0MzYyODgxNjU0NzIwMTg0MzkxMzc3NA
The files furthest down are the project files with their unique ID as their filename.
All the URLs in this section work relative to both these URLs: /{instanceId}/students/{studentId}/courses/{courseId}/exercises/{exerciseId}/snapshots/
and /{instanceId}/courses/{courseId}/exercises/{exerciseId}/students/{studentId}/snapshots/
.
Method: GET
Content-Type: application/json
URL: /{snapshotId}/files/
Returns: A list of all the files for the requred snapshot as it relates to the start of the URL
GET /hy/students/dXNlcjE/courses/czIwMTQtdGlyYQ/exercises/dmlpa2tvMDEtdGlyYTEuMQ/snapshots/140943627771047191388761820/files/
[
{
"id": "c3JjL01haW4uamF2YTE0MDk0MzYyNzc3MTA0NzE5MTM4ODc2MTgyMA",
"name": "Main.java",
"path": "src/Main.java"
}
]
Method: GET
Content-Type: application/json
URL: /{snapshotId}/files/{fileId}/
Returns: A single file for the requested snapshot as it relates to the start of the URL
GET /hy/students/dXNlcjE/courses/czIwMTQtdGlyYQ/exercises/dmlpa2tvMDEtdGlyYTEuMQ/snapshots/140943627771047191388761820/files/c3JjL01haW4uamF2YTE0MDk0MzYyNzc3MTA0NzE5MTM4ODc2MTgyMA/
{
"id": "c3JjL01haW4uamF2YTE0MDk0MzYyNzc3MTA0NzE5MTM4ODc2MTgyMA",
"name": "Main.java",
"path": "src/Main.java"
}
Method: GET
Content-Type: text/plain
URL: /{snapshotId}/files/{fileId}/content/
Returns: The content of the specified file as it relates to the start of the URL
GET /hy/students/dXNlcjE/courses/czIwMTQtdGlyYQ/exercises/dmlpa2tvMDEtdGlyYTEuMQ/snapshots/140943627771047191388761820/files/c3JjL01haW4uamF2YTE0MDk0MzYyNzc3MTA0NzE5MTM4ODc2MTgyMA/content/
public class Main {
public static void main(String[] args) {
System.out.println("Hello API");
}
}
All the URLs in this section work relative to both these URLs: /{instanceId}/students/{studentId}/courses/{courseId}/exercises/{exerciseId}/
and /{instanceId}/courses/{courseId}/exercises/{exerciseId}/students/{studentId}/
.
Method: GET
Content-Type: application/json
URL: /tags/
Returns: A list of tags for the specified exercise
GET /hy/students/dXNlcjE/courses/czIwMTQtdGlyYQ/exercises/dmlpa2tvMDEtdGlyYTEuMQ/tags/
[
{
"name": "tag1"
},
{
"name": "tag2"
}
]
Method: POST
Content-Type: application/json
URL: /tags/
Returns: The created tag
POST /hy/students/dXNlcjE/courses/czIwMTQtdGlyYQ/exercises/dmlpa2tvMDEtdGlyYTEuMQ/tags/
{
"name": "tag1"
}
Method: DELETE
Content-Type: application/json
URL: /tags/{tagId}/
Returns: The deleted tag
DELETE /hy/students/dXNlcjE/courses/czIwMTQtdGlyYQ/exercises/dmlpa2tvMDEtdGlyYTEuMQ/tags/1/
{
"name": "tag1"
}
This project has been developed at the University of Helsinki’s Department of Computer Science by:
This project is licensed under GPL2.