Programmatic Endpoints
Client side libraries take care of reporting skills and visualizing display results, however there are times when you may want to call programmatic endpoints directly.
Some examples include:
- You may not be able to use one of the supported frameworks to reports skills
- You may need to report skill events from server side components
Please Note
If you are looking for endpoints to retrieve progress and ranking data, that is not supported by the SkillTree platform. In liu of those endpoints and in order to support rapid integration SkillTree has taken an innovative approach of supplying fully navigable Ranking and Visualization views. Please take a look at the Integration Guide Overview to learn more.
Public Endpoints (only 1 so far):
[Service URL]
/api/projects/[Project Id]
/skills/[Skill Id]
- HTTP Methods: POST, PUT
- Purpose: Report Skill Events
- Detailed Description: Click Here
This endpoint requires authentication and a user id in order to perform its functions. Please select your installation type below for specific instructions:
In Password Auth Installation, the OAuth2 protocol is utilized, you will need to:
- retrieve user specific temporary client token
- using project's
Client ID
andClient Secret
(found in the dashboard underProject -> Access -> 'Trusted Client Properties'
). user-to-proxy-for
is provided in the request (this is theuser id
).- result token encapsulates the
user id
so the service will know what user to perform this action for
- using project's
- call the endpoint and set the user token on the request.
Here is a CURL based example: (please substitute your values of client-id
, client-secret
, dashboard-url
and user-to-proxy-for
):
curl client-id:client-secret@dashboard-url/oauth/token -d "grant_type=client_credentials&proxy_user=user-to-proxy-for"
and then (please substitute your values of access_token_from_first_call
, dashboard-url
):
curl -H "Authorization: Bearer access_token_from_first_call" http://dashboard-url/api/projects/FirstProject/level
Report Skill Event Endpoint
If the existing libraries do not suffice or you need to report skill events from your server components (e.g., batch, async, streaming, etc..), then you can [POST](https://en.wikipedia.org/wiki/POST_(HTTP) / PUT to the endpoint directly in order to report a single skill event:
[Service URL]
/api/projects/[Project Id]
/skills/[Skill Id]
where
- Service URL: Fully qualified URL of the skills service/dashboard, if you are running it locally then something like
http://localhost:8082
- Project Id: Project id for the reported skill
- Skill Id: For the reported skill
For example, to report a skill with id SkillA
for a project with id ProjectA
, for a locally hosted service, POST to the following URL:
http://localhost:8080/api/projects/ProjectA/skills/SkillA
The Report Skill Endpoint also accepts optional JSON payload parameters.
Parameter | Explanation |
---|---|
userId | (optional) Report skill event on behalf of another user (must be an admin of the project). |
timestamp | (optional) Report skill event in the past (must be an admin of the project). |
notifyIfSkillNotApplied | (optional) If set to true , notify all client global event handlers even if the reported skill is not applied. Defaults to false . |
Here is an example JSON payload for reporting a skill event for another user in the past:
{
"userId":"valueForUserId",
"timestamp":1581349194294,
"notifyIfSkillNotApplied": false
}
Keep In Mind
Only a project admin is allowed to supply userId
and timestamp
.
Keep In Mind
Only a project admin is allowed to supply userId
and timestamp
.
Endpoint Result Object
Skill events are applied immediately and atomically based on the currently configured ruleset (via dashboard). The endpoint returns an object that depicts how this event affected the user's progress.
Event result object provides:
- status - whether skill was applied or rejected
- if skill was rejected, reason for that rejection
- achievements completed by this event including
- completion of a skill
- leveling-up for a project or a subject
- achievement of a badge or a gem
Here is an example of an event that (1) was successfully applied, (2) completed/achieved that skill, and (3) achieved level 2 for subject named Cool Subject
{
"success":true,
"projectId":"sampleProject",
"skillId":"ImportantSkill",
"name":"Important Skill",
"pointsEarned": 15,
"totalPointsEarned": 30,
"totalPoints": 30,
"numOccurrencesToCompletion": 2,
"skillApplied":true,
"explanation":"Skill event was applied",
"completed":[{
"type":"Subject",
"level":2,
"id":"CoolSubjectId",
"name":"Cool Subject"
}, {
"type":"Skill",
"level":null,
"id":"ImportantSkill",
"name":"This is a very important skill"
}]
}
Here is a reference table for result fields and their meaning:
Field | Type | Explanation |
---|---|---|
success | boolean | true if there were no issues reporting the skill, false if there was a server side failure - this could happen if the service is down or you stumbled on a bug |
projectId | string | the projectId that the report skill belongs to |
skillId | string | the skillId of the report skill |
name | string | the display name of the report skill |
pointsEarned | number | number of points earned by this request |
totalPointsEarned 🕓 Since skills-service:3.3 | number | total points earned by this user for this skill |
totalPoints 🕓 Since skills-service:3.3 | number | total points defined by an administrator for this skill |
numOccurrencesToCompletion 🕓 Since skills-service:3.3 | number | number of times skill needs to be performed to earn all its points |
skillApplied | boolean | true if this event contributed points to the skill; false if the event didn't contribute points - explanation field will tell you why (see examples below) |
explanation | string | human readable explanation about how this skill event was handled; this field will explain why an event wasn't able to contribute points (see examples below) |
completed | list | metadata of a completed item if this event caused user to level-up, complete a skill or earn a badge/gem (just to mention a few) |
completed.type | string | type of the completed item, will be one of these well-known values: Overall , Subject , Skill , Badge . Overall indicates that the user leveled-up for the entire project, Subject indicates that the user leveled-up for a specific subject, Skill indicates that this skill is fully accomplished, Badge indicates that a badge/gem was earned. |
completed.level | int | indicates which level the user achieved via this skill event; only applicable to Overall and Subject types |
completed.id | string | id of the completed item, in the case of Skill type this will be skill id, in the case of Subject type it will be subject id and so on... |
completed.name | string | human friendly name of the event and can be used to display to the end user |
Here is an example where the skill event did not contribute any points because it's already fully accomplished:
{
"success":true,
"projectId":"sampleProject",
"skillId":"ImportantSkill",
"name":"Important Skill",
"pointsEarned": 0,
"totalPointsEarned": 200,
"totalPoints": 200,
"numOccurrencesToCompletion": 2,
"skillApplied":false,
"explanation":"This skill reached its maximum points",
"completed":[]
}
Here is an example where the skill event did not contribute any points because it has unfulfilled dependencies:
{
"success":true,
"projectId":"sampleProject",
"skillId":"ImportantSkill",
"name":"Important Skill",
"pointsEarned": 0,
"totalPointsEarned": 0,
"totalPoints": 200,
"numOccurrencesToCompletion": 2,
"skillApplied":false,
"explanation":"Not all dependent skills have been achieved. Missing achievements for 1 out of 1. Waiting on completion of [FirstProject:skill1Skill].",
"completed":[]
}
Below is an example where the skill contributed points but did not complete anything:
{
"success":true,
"projectId":"sampleProject",
"skillId":"ImportantSkill",
"name":"Important Skill",
"pointsEarned": 15,
"totalPointsEarned": 30,
"totalPoints": 45,
"numOccurrencesToCompletion": 3,
"skillApplied":true,
"explanation":"Skill event was applied",
"completed":[]
}
Above skill has Occurrences to Completion > 1
and additional skill events must be reported to fulfill the required occurrences. Once all of the required occurrences are reported then the skill completion will appear in the completed field.
Tips
You can use this result object to implement a messaging center - to report messages of encouragement to your users as they complete skills, level-up and earn badges.
Java Examples
Reporting skill event programmatically is two-fold:
- Retrieve token for a specific user id
- utilize
Client Id
andClient Secret
found underTrusted Client Properties
on project'sAccess
page
- utilize
- Using the token report the event for a skill id
- if the token retrieved in step 1 has Admin privileges then the skill can be reported for any user, otherwise only for the user represented by the token
Here is an example of retrieving a token for a given user and reporting one skill for that user:
public class ReportExample {
public static void main(String[] args) throws Exception {
// "Client Id" and "Client Secret" found under
// "Trusted Client Properties" on project's "Access" page
ReportExample reportJavaExample =
new ReportExample(
"<PROJECT_ID>",
"<SECRET>",
"<PROTOCOL>",
"<HOST>");
String token = reportJavaExample.getToken("<USER_ID>");
String res = reportJavaExample.reportSkill(token, "<SKILL_ID>");
System.out.println(res);
}
private final String projectId;
private final String secret;
private final String protocol;
private final String host;
public ReportExample(String projectId,
String secret,
String protocol,
String host) {
this.projectId = projectId;
this.secret = secret;
this.protocol = protocol;
this.host = host;
}
public String getToken(String userID) throws Exception {
String authUrl = protocol + "://"+ projectId +
":" + secret + "@" + host + "/oauth/token";
List<NameValuePair> authParameters = new ArrayList<>();
authParameters.add(
new BasicNameValuePair("grant_type", "client_credentials"));
authParameters.add(
new BasicNameValuePair("proxy_user", userID));
HttpPost authPost = new HttpPost(authUrl);
authPost.setEntity(new UrlEncodedFormEntity(authParameters));
String token = "";
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(authPost)) {
String tokenInfo = EntityUtils.toString(response.getEntity());
JSONObject tokenJson = new JSONObject(tokenInfo);
token = (String) tokenJson.get("access_token");
}
return token;
}
public String reportSkill(String token, String skillId)
throws Exception {
String reportUrl = protocol + "://"+
host + "/api/projects/" + projectId + "/skills/" + skillId;
HttpPost post = new HttpPost(reportUrl);
post.setHeader("Authorization", "Bearer " + token);
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(post)) {
return EntityUtils.toString(response.getEntity());
}
}
}
Here is an example of retrieving a token for a user with project admin privileges and then reporting a skill for a different user:
public class ReportForAnotherUserExample {
public static void main(String[] args) throws Exception {
// "Client Id" and "Client Secret" found under
// "Trusted Client Properties" on project's "Access" page
ReportForAnotherUserExample reportJavaExample =
new ReportForAnotherUserExample(
"<PROJECT_ID>",
"<SECRET>",
"<PROTOCOL>",
"<HOST>");
// must be an admin of <project_id>
String token = reportJavaExample.getToken("<USER_ID>");
String res = reportJavaExample.reportSkillForAnother(
token,
"<ANOTHER_USER_id>",
"<SKILL_ID>",
new Date());
System.out.println(res);
}
private final String projectId;
private final String secret;
private final String protocol;
private final String host;
public ReportForAnotherUserExample(
String projectId, String secret,
String protocol, String host) {
this.projectId = projectId;
this.secret = secret;
this.protocol = protocol;
this.host = host;
}
public String getToken(String userID) throws Exception {
String authUrl = protocol + "://"+
projectId + ":" + secret + "@" + host + "/oauth/token";
// First setup token
List<NameValuePair> authParameters = new ArrayList<>();
authParameters.add(
new BasicNameValuePair("grant_type", "client_credentials"));
authParameters.add(
new BasicNameValuePair("proxy_user", userID));
HttpPost authPost = new HttpPost(authUrl);
authPost.setEntity(new UrlEncodedFormEntity(authParameters));
String token = "";
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(authPost)) {
String tokenInfo = EntityUtils.toString(response.getEntity());
JSONObject tokenJson = new JSONObject(tokenInfo);
token = (String) tokenJson.get("access_token");
}
return token;
}
public String reportSkillForAnother(String token,
String pointsForThisUser,
String skillId,
Date performedOn) throws Exception {
String reportUrl = protocol + "://" +
host + "/api/projects/" + projectId + "/skills/" + skillId;
HttpPost post = new HttpPost(reportUrl);
post.setHeader("Authorization", "Bearer " + token);
// Add request parameters
String jsonString = "{\"userId\":\"" +
pointsForThisUser + "\", \"timestamp\":\"" +
performedOn.getTime() + "\"}";
post.setEntity(
new StringEntity(jsonString, ContentType.APPLICATION_JSON));
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(post)) {
return EntityUtils.toString(response.getEntity());
}
}
}
This example is using Apache HttpClient library so you will need to add it to your classpath. For example, in Maven it would look something like this:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${version}</version>
</dependency>