Restful API
The WebApi extension from jobbrIO/jobbr-webapi adds a Rest-style management interface to jobbr.
Installation
Install the NuGet Jobbr.Server.WebAPI
to the project where you host you Jobbr-Server. The extension already comes with a small webserver based on OWIN/Katana. The referenced HttpListenr will be installed by NuGet automatically.
Install-Package Jobbr.Server.WebAPI
Registration
The Library comes with an extension method for the JobbrBuilder
. To add the Web API to a Jobbr-Server you need to register it prior calling start as you see below. Please note that this is not an ASP.NET WebAPI when registering it to an OWIN Pipeline, although we’re using the same principle. (In fact, we’re using WebAPI internally)
1using Jobbr.Server.WebAPI;
2
3// ....
4
5// Create a new builder which helps to setup your JobbrServer
6var builder = new JobbrBuilder();
7
8// Register the extension
9builder.AddWebApi();
10
11// Create a new instance of the JobbrServer
12var server = builder.Create();
13
14// Start
15server.Start();
Plugin Configuration
If you don’t specify any value for BackendAddress
the server will try to find a free port automatically and bind to all available interfaces. The endpoint is logged and usually shown in the console, but this approach is not recommended for production scenarios, see below:
[WARN] (Jobbr.Server.WebAPI.Core.WebHost) There was no BackendAdress specified. Falling back to random port, which is not guaranteed to work in production scenarios
....
[INFO] (Jobbr.Server.JobbrServer) The configuration was validated and seems ok. Final configuration below:
JobbrWebApiConfiguration = [BackendAddress: "http://localhost:1903"]
You can override this behavior, by explicitly providing your own URI prefix, for instance http://localhost:8765/api
. See example below:
1builder.AddWebApi(config =>
2{
3 config.BaseUrl = "http://localhost:8765/api";
4});
Note: Please refer to the MSDN Documentation for HttpListener for the supported URI prefixes depending on your operating system and .NET Runtime version.
Rest API Reference
/jobs Endpoint
You could either configure your Jobs by the RepositoryBuilder in C# code or create them by using the API, or both. The followig APIs are made for managing Jobs
Get all Jobs
The following endpoint returns all registered jobs as an array:
GET http://localhost:8765/api/jobs HTTP/1.1
Successful Response
Is indicated by
HTTP/1.1 200 OK
Content-Type: application/json
and the following example payload
[
{
"id": 1,
"uniqueName": "ProgressJob",
"type": "Demo.MyJobs.ProgressJob",
"parameters": {
"param1" : "test",
"param2" : "anothervalue"
},
"createdDateTimeUtc": "2015-03-04T17:40:00",
"createdDateTimeUtc": "2017-07-30T13:40:00"
}
]
Single Job details
Details about a single job (including triggers) can be retrieved by accessing the detail route of a job
GET http://localhost:8765/api/jobs/1 HTTP/1.1
Sucessful Response
If the job is found, the response is indicated by
HTTP/1.1 200 OK
Content-Type: application/json
and the following example data is returned. Note the addition of Triggers
{
"id": 1,
"uniqueName": "ProgressJob",
"type": "Demo.MyJobs.ProgressJob",
"parameters": {
"param1" : "test",
"param2" : "anothervalue"
},
"createdDateTimeUtc": "2015-03-04T17:40:00",
"createdDateTimeUtc": "2017-07-30T13:40:00",
"trigger": [
{
"triggerType": "Recurring",
"id": 1,
"isActive": true
}
]
}
Error Responses
If no job exists with the given id, an error will be returned
Add a new Job
Besides the RepositoryBuilder in C#, there’s also a possibility to create jobs by the Rest API.
Parameters
uniqueName
: Unique name of the job (Required)type
: Name of the CLR Type that should be used (Required)parameters
: Object that will be used as JobParameters
Sample Request
POST http://localhost:8765/api/jobs HTTP/1.1
Content-Type: application/json
[
{
"id": 1,
"uniqueName": "ProgressJob",
"type": "Demo.MyJobs.ProgressJob",
"parameters": {
"param1" : "jobParameter1",
"param2" : "anothervalue"
}
},
]
Successful Response
201 Created
Location: /api/jobs/2
Content-Type: application/json
and the payload
{
"uniqueName": "ProgressJob2",
"type": "Demo.MyJobs.ProgressJob"
}
Error Responses
If there is already a job with the same UniqueName, the error 409 CONFLICT
will be returned.
JobRuns for Job
If you wan’t to get all runs for a specific job, you can use the subresource runs
on every job. A job can be identified by its internal id
or the user specific uniqueName
.
Url Parameters
id
: Internal Id of the Job (Required)uniqueName
: Unique name if the job (Required)
GET http://localhost:8765/api/jobs/1/runs
GET http://localhost:8765/api/jobs/progressJob/runs
Successful Response
which will be replied with
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"jobId": 1,
"triggerId": 1,
"jobRunId": 1,
"state": "Completed",
"progress": 100,
"plannedStartUtc": "2017-07-30T10:53:00Z",
"auctualStartUtc": "2017-07-30T10:53:00.5132852Z",
"auctualEndUtc": "2017-07-30T10:53:19.335589Z"
},
]
Note: Only single entry shown.
/triggers Endpoint
Triggers are used to either add future or instant triggers to a job. The trigger is causing a job to run. Triggers are a subresource of /jobs
There are different types of triggers, each with additional attributes:
instant
: Schedules a job run that runs immediately (can be delayed by the propertydelayedMinutes
)scheduled
: Schedules a a jobrun that starts on the specifiedstartDateTimeUtc
recurring
: Recurring trigger with a cron definition indefinition
which is valid betweenstartDateTimeUtc
andendDateTimeUtc
. IfnoParallelExecution
flag is set totrue
, the trigger won’t trigger a new job run if one instance of that job is already running (job run is omitted).
The trigger type itself is specified by the property triggerType
.
Get all Triggers for a Job
Triggers are attached to a job and therefore accessible as a subresource of a job identified by its internal id
or the specified uniqueName
.
Url Parameters
id
: Internal Id of the Job (Required)uniqueName
: Unique name if the job (Required)
Jobs can be identified by both their id
or uniqueName
GET http://localhost:8765/api/jobs/1/triggers
GET http://localhost:8765/api/jobs/progressJob/triggers
Successful Response
which will be replied with a list of all triggers for this job where some of the properties are valid for all types while others are only applicable to certain types
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id": 1,
"jobId": 1,
"isActive": true,
"comment": "Send the report now!!!",
"parameters": {
"printReportId" : "12",
"recpient": "me@inbox.com",
},
"userId": "user123",
"userDisplayName": "Michael Schnyder",
"delayedMinutes": 0,
},
{
"id": 2,
"jobId": 1,
"isActive": true,
"comment": "Send report once at 3pm",
"parameters": {
"printReportId" : "12",
"recpient": "anotherguy@inbox.com",
},
"userId": "user123",
"userDisplayName": "Michael Schnyder",
"startDateTimeUtc": "2017-07-30T15:00:00Z",
},
{
"id": 3,
"jobId": 1,
"isActive": true,
"comment": "Daily Report @ 9pm",
"parameters": {
"printReportId" : "12",
"recpient": "anotherguy@inbox.com",
},
"userId": "user123",
"userDisplayName": "Michael Schnyder",
"definition": "0 15 * * *",
"startDateTimeUtc": "2017-01-1T00:00:00Z",
"endDateTimeUtc": "2022-12-31T00:00:00Z",
"noParallelExecution": true
},
]
Please note that the API does not expose the trigger types on the list level.
Single Trigger details
If you want to get one specific trigger only, you need to address the trigger directly as a subresource of the job.
Schema: http://localhost:8765/api/jobs/[jobId]/triggers/[triggerId]
where:
jobId
: Internal Id of the Job (Required)triggerId
: Id of the trigger (Required)
Example request
GET http://localhost:8765/api/jobs/1/triggers/3
Successful response
HTTP/1.1 200 OK
Content-Type: application/json
With payload
{
"id": 3,
"triggerType": "recurring",
"jobId": 1,
"isActive": true,
"comment": "Daily Report @ 9pm",
"parameters": {
"printReportId" : "12",
"recpient": "anotherguy@inbox.com",
},
"userId": "user123",
"userDisplayName": "Michael Schnyder",
"definition": "0 15 * * *",
"startDateTimeUtc": "2017-01-1T00:00:00Z",
"endDateTimeUtc": "2022-12-31T00:00:00Z",
"noParallelExecution": true
}
Note: The type of the trigger is now exposed by the property
triggerType
.
Add a trigger
Please note that each trigger type has a couple of properties that are common, especially
triggerType
: Type of the trigger, see above (Required)isActive
: Specifies if the trigger is active (Required)parameters
: Object that will be used as RunParameterscomment
: Any arbitrary comment or additional information for this triggeruserId
: The principal under which the job should be starteduserDisplayName
: Any arbitrary that could be the name of the user that triggered the job
Both
uniqueName
and internal jobid
is supported on this route. Examples only show identification of job by internal id
Example Request (Instant)
The minimal example to add an instant trigger is shown below:
POST http://localhost:8765/api/jobs/1/triggers HTTP/1.1
Content-Type: application/json
{
"triggerType" : "instant"
}
isActive
is not required and will be automatically set totrue
, because a non-active instant trigger would be a joke.
Optional Properties (Type related)
delayedMinutes
: Amount of time (in minutes) in which the start shall be delayed
Example Request (Scheduled)
The minimal example to add an scheduled trigger is shown below:
POST http://localhost:8765/api/jobs/1/truggers HTTP/1.1
Content-Type: application/json
{
"triggerType" : "instant",
"isActive": true,
"startDateTimeUtc": "2017-07-30T15:00:00Z",
}
Optional Properties (Type related)
none
Example Request (Recurring)
The minimal example to add an recurring trigger is shown below:
POST http://localhost:8765/api/jobs/1/triggers HTTP/1.1
Content-Type: application/json
{
"triggerType" : "recurring",
"isActive": true,
"definition": "0 23 * * *",
}
Optional Properties (Type related)
startDateTimeUtc
: Start of time range when trigger is validendDateTimeUtc
: End of time range when trigger is validnoParallelExecution
: Indicates if this trigger is allowed to cause a new job while a job caused by the same trigger is still running.
Successful Response
A successful response will return the created trigger and the location to its details by a 201 Created
Response.
Example
201 Created
Location: /api/jobs/1/triggers/4
Content-Type: application/json
and the payload
{
"id": 4,
"triggerType" : "recurring",
"isActive": true,
"definition": "0 23 * * *",
}
Update a Trigger
In the rare cases you’ll need to update a trigger before the job run has actually started, there is an endpoint for patching existing triggers of a job
Schema: http://localhost:8765/api/jobs/[jobId]/triggers/[triggerId]
where:
jobId
: Internal Id of the Job (Required)triggerId
: Id of the trigger (Required)
Only the following changes are possible
Change
isActive
fromtrue
tofalse
or vice-versaAdjust Cron-Definition of a Recurring-Trigger
Change
StarteDateUtc
to any value in the future of a ScheduledTrigger
Each request needs to contain the following properties
isActive
: Specifies if the trigger is active (Required)triggerType
: Type of the trigger, see above (Required for non-instant trigger types)
Sample Request (Instant)
To disable the trigger with id 1, the following call needs to be executed:
PATCH http://localhost:8765/api/jobs/1/triggers/1 HTTP/1.1
Content-Type: application/json
{
"isActive": false,
},
Sample Request (Scheduled)
To update the scheduled start of a trigger to anything else in future, the following call is required:
PATCH http://localhost:8765/api/jobs/1/triggers/2 HTTP/1.1
Content-Type: application/json
{
"triggerType": "scheduled",
"isActive": true,
"startDateTimeUtc": "2017-08-04T23:00:00Z",
},
Sample Request (Recurring)
To update the scheduled start of a trigger to anything else in future, the following call is required:
PATCH http://localhost:8765/api/jobs/1/triggers/3 HTTP/1.1
Content-Type: application/json
{
"triggerType": "recurring",
"isActive": true,
"definition": "0 22 * * *",
},
/jobruns Endpoint
Jobruns are a result of a job and a trigger that has caused the jobrun itself. JobRuns are read-only.
Query JobRuns
There is no possibility to get all jobruns, but there are query options that allow querying jobruns by
userId
: Example:http://localhost:8765/api/jobruns?userId=user123
userDisplayName
: Example:http://localhost:8765/api/jobruns?userDisplayName=Testuser
jobId
andtriggerId
: Example:http://localhost:8765/api/jobruns?jobId=3&triggerId=4
Successful Response
A list of matching jobruns will be returned:
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"jobId":1,
"triggerId":3,
"jobRunId":1,
"jobName":"ProgressJob",
"state":"Completed",
"progress":100.0,
"plannedStartUtc":"2017-08-02T20:25:00Z",
"auctualStartUtc":"2017-08-02T20:25:00.4674296Z",
"auctualEndUtc":"2017-08-02T20:25:18.8927592Z",
"jobTitle":"ProgressJob",
"jobParameter": {
"param1" : "jobParameter1",
"param2" : "anothervalue"
},
"instanceParameter": {
"printReportId" : "12",
"recpient": "anotherguy@inbox.com",
},
"artefacts": [
{
"filename": "report.log",
"size": 1258,
"contentType": "text/plain"
},
{
"filename": "sent-mail.eml",
"size": 258478,
"contentType": "message/rfc822"
}
]
},
{
"jobId":1,
"triggerId":3,
"jobRunId":2,
"jobName":"ProgressJob",
"state":"Processing",
"progress":78.0,
"plannedStartUtc":"2017-08-02T20:26:00Z",
"auctualStartUtc":"2017-08-02T20:26:00.4682476Z",
"jobTitle":"ProgressJob",
"jobParameter": {
"param1" : "jobParameter1",
"param2" : "anothervalue"
},
"instanceParameter": {
"printReportId" : "12",
"recpient": "anotherguy@inbox.com",
}
},
]
Note that the second job has not yet completed and thus did not collect any artefacts from the Run-Directory.
Single JobRun details
More detailed information about a specific JobRun can be found on the JobRun details route.
GET http://localhost:8765/api/jobruns/1 HTTP/1.1
Sucessful Response
If the jobrun is found, the response is indicated by
HTTP/1.1 200 OK
Content-Type: application/json
and the following example data is returned. Note the addition of Triggers
{
"jobId":1,
"triggerId":3,
"jobRunId":1,
"jobName":"ProgressJob",
"state":"Completed",
"progress":100.0,
"plannedStartUtc":"2017-08-02T20:25:00Z",
"auctualStartUtc":"2017-08-02T20:25:00.4674296Z",
"auctualEndUtc":"2017-08-02T20:25:18.8927592Z",
"jobTitle":"ProgressJob",
"jobParameter": {
"param1" : "jobParameter1",
"param2" : "anothervalue"
},
"instanceParameter": {
"printReportId" : "12",
"recpient": "anotherguy@inbox.com",
},
"artefacts": [
{
"filename": "report.log",
"size": 1258,
"contentType": "text/plain"
},
{
"filename": "sent-mail.eml",
"size": 258478,
"contentType": "message/rfc822"
}
]
}
Download Artefact
Artefacts are listed as object array in the property artefacts
. To download a specific artefact, a GET
-Request is required.
http://localhost:8765/api/jobruns/1/artefact/report.log HTTP/1.1
and the file with the approriate headers will be returned
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Lenght: 1258
...
Generic Endpoints
/status
The status endpoint is for testing purposes only. Even if it does not perform health checking it can be used to determine the HTTP bindings and general availability of the Http-Endpoint.
GET http://localhost:8765/api/status HTTP/1.1
Does usually just return:
HTTP/1.1 200 OK
"Fine"
/configuration
If you need to check the current configuration, use the /configuration
endpoint.
GET http://localhost:8765/api/status
Which will return a object that represents the current Web-API configuration.
HTTP/1.1 200 OK
{
"backendAddress": "http://localhost:8765/api"
}
/fail
If you are curious if logging is setup correctly or if any reverse proxies are interfering with HTTP 500 error codes, you can use this endpoint
GET /fail HTTP/1.1
Will raise an unhandled exception and usually shows an error response similar to
HTTP/1.1 500 Internal Server Error
{
"message": "An error has occurred.",
"exceptionMessage": "This has failed!",
"exceptionType": "System.Exception",
"stackTrace": " at Jobbr.Server.WebAPI.Core.Controller.DefaultController.Fail() in DefaultController.cs:line 42
...
}
Static Typed C#-Client
There is also a static typed client available which you can use to interact with any Jobbr Rest API. Install the client by using the following commands
Install-Package Jobbr.Client
After installation, you must provide the base url where the API can be found. See example below
1using Jobbr.Client;
2using Jobbr.Server.WebAPI.Model;
3
4// ...
5
6var jobbrClient = new JobbrClient("http://localhost:8765/api");
7
8var allJobs = jobbrClient.GetAllJobs();
Limitations
Authentication
Currently there is no authentication middleware available and the API should therefore not be exposed to the public. However this feature is planned in the future