Small REST API Service that provides core device management and service handling. This stateless service allows you to manage devices, services and provides comprehensive cost reports.
The diagram bellow represents a future version of this application using Microservice Architecture hosted on AWS Cloud services.
- Java 11
- Spring Boot 2.4.2
- Spring 5.2
- Docker
- PostgresSQL 13
- JWT
- Liquibase 3
- Spring JPA
- JUnit 5.7
- Mockito 3.6
- Gradle 6
URL | Method | Description |
---|---|---|
Authentication: | ||
/api/v1/auth/login | POST | Authenticate user with username and password |
Device Management: | ||
/api/v1/companies/{companyId}/devices | GET | List all devices for the given company id |
/api/v1/companies/{companyId}/devices | POST | Create a device for the given company id |
/api/v1/companies/{companyId}/devices/{id} | PUT | Update the given device information |
/api/v1/companies/{companyId}/devices/{id} | DELETE | Delete the given device for the company id |
Management of services for Devices : | ||
/api/v1/companies/{companyId}/devices/{id}/services | POST | Add a service to the given device |
/api/v1/companies/{companyId}/devices/{id}/services/{id} | DELETE | Remove the specified service for the given device |
Company Services Summary: | ||
/api/v1/companies/{companyId}/services | GET | List all services and number of devices |
Company Monthly Billing Summary: | ||
/api/v1/companies/{companyId}/monthly-cost | GET | Generates a summary containing services and total monthly cost |
POST http://localhost:8000/api/v1/auth/login
Content-Type: application/json
Payload:
{
"username": "admin",
"password": "Pa$$word"
}
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"username": "admin",
"token": "Bearer xxx.yyy.zzz"
}
GET http://localhost:8000/api/v1/companies/{companyId}/devices
Authorization: Bearer xxx.yyy.zzz
Response:
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id": "45cc44b8-8ba4-4210-bf16-7fd0f1b69db2",
"companyId": "0ee4a0fa-224c-4b0b-ac22-101acab87b7b",
"systemName": "Domain Controller",
"type": "WINDOWS_SERVER",
"createdAt": "2021-01-31T23:18:09.178481",
"updatedAt": "2021-01-31T23:18:09.180195"
},
{
"id": "54d6810f-5e81-408d-a16d-04f1fbfbad8d",
"companyId": "0ee4a0fa-224c-4b0b-ac22-101acab87b7b",
"systemName": "Mac workstation",
"type": "MAC",
"createdAt": "2021-01-31T23:19:33.994986",
"updatedAt": "2021-01-31T23:19:33.995007"
}
]
POST http://localhost:8000/api/v1/companies/{companyId}/devices
Authorization: Bearer xxx.yyy.zzz
Content-Type: application/json
Payload:
{
"systemName": "Mac workstation",
"type": "MAC"
}
Body Parameters:
Name | Type | Required | Accepted values | Default | Description |
---|---|---|---|---|---|
systemName | String | Yes | Name of the device | ||
type | String | Yes | ["WINDOWS_SERVER", "WINDOWS_WORK_STATION", "MAC"] | Type of device |
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "54d6810f-5e81-408d-a16d-04f1fbfbad8d",
"companyId": "0ee4a0fa-224c-4b0b-ac22-101acab87b7b",
"systemName": "Mac workstation",
"type": "MAC",
"createdAt": "2021-01-31T23:19:33.994986",
"updatedAt": "2021-01-31T23:19:33.995007"
}
PUT http://localhost:8000/api/v1/companies/{companyId}/devices/{deviceId}
Authorization: Bearer xxx.yyy.zzz
Content-Type: application/json
Payload:
{
"systemName": "New system name",
"type": "Windows Server"
}
Body Parameters:
Name | Type | Required | Accepted values | Default | Description |
---|---|---|---|---|---|
systemName | String | Yes | Name of the device | ||
type | String | Yes | ["WINDOWS_SERVER", "WINDOWS_WORK_STATION", "MAC"] | Type of device |
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "54d6810f-5e81-408d-a16d-04f1fbfbad8d",
"companyId": "0ee4a0fa-224c-4b0b-ac22-101acab87b7b",
"systemName": "New system name",
"type": "WINDWS_SERVER",
"createdAt": "2021-01-31T23:19:33.994986",
"updatedAt": "2021-01-31T23:19:33.995007"
}
DELETE http://localhost:8000/api/v1/companies/{companyId}/devices/{deviceId}
Authorization: Bearer xxx.yyy.zzz
Response:
HTTP/1.1 204 No Content
POST http://localhost:8000/api/v1/companies/{companyId}/devices/{id}/services
Authorization: Bearer xxx.yyy.zzz
Content-Type: application/json
Payload:
{
"serviceId": "1b023d42-1502-4e3e-acf2-f91d8ca50baf"
}
Body Parameters:
Name | Type | Required | Accepted values | Default | Description |
---|---|---|---|---|---|
serviceId | String | Yes | UUID of the service to be added to the device |
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "2e0c4603-2a4e-45be-8398-a9c7ecec5b29",
"serviceId": "1b023d42-1502-4e3e-acf2-f91d8ca50baf",
"serviceName": "Windows Antivirus",
"serviceDescription": "",
"purchasedAt": "2021-01-31T23:42:22.047565"
}
DELETE http://localhost:8000/api/v1/companies/{companyId}/devices/{deviceId}/services/{deviceServiceId}
Authorization: Bearer xxx.yyy.zzz
Response:
HTTP/1.1 204 No Content
GET http://localhost:8000/api/v1/companies/{companyId}/services
Authorization: Bearer xxx.yyy.zzz
Response:
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id": "1b023d42-1502-4e3e-acf2-f91d8ca50baf",
"name": "Windows Antivirus",
"description": "",
"price": 5,
"numberOfDevices": 1
},
{
"id": "3986ccb1-0890-451b-b819-e48b5b83ccab",
"name": "Mac Antivirus",
"description": "",
"price": 7,
"numberOfDevices": 1
},
{
"id": "73b27887-4da7-451f-bb91-c9fd3989c89e",
"name": "TeamViewer",
"description": "",
"price": 2,
"numberOfDevices": 2
},
{
"id": "9ea98956-7651-42e8-a704-a55acb55ea1d",
"name": "Cloudberry",
"description": "",
"price": 3,
"numberOfDevices": 2
},
{
"id": "f8bb1483-2e08-49ea-a506-c726cd0a2d6c",
"name": "PSA",
"description": "",
"price": 2,
"numberOfDevices": 2
}
]
GET http://localhost:8000/api/v1/companies/{companyId}/monthly-cost
Authorization: Bearer xxx.yyy.zzz
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"totalCost": 34,
"services": [
{
"serviceName": "Windows Antivirus",
"cost": 5
},
{
"serviceName": "Mac Antivirus",
"cost": 7
},
{
"serviceName": "TeamViewer",
"cost": 4
},
{
"serviceName": "Cloudberry",
"cost": 6
},
{
"serviceName": "PSA",
"cost": 4
},
{
"serviceName": "Devices cost",
"cost": 8
}
]
}
Let's clone the repo from Github using the following command:
$ git clone git@github.com:mookofe/rmm-services-server-app.git
Next step setup PostgresSQL using docker:
$ cd rmm-services-server-app
$ docker-compose up -d
Run tests:
$ ./gradlew test
Execute Application:
$ ./gradlew bootRun
For a straight forward development setup I'm using Liquibase to generate the database schema and data seeding.
Companies:
id | name |
---|---|
0ee4a0fa-224c-4b0b-ac22-101acab87b7b | Demo Company |
Services:
id | name | price |
---|---|---|
1b023d42-1502-4e3e-acf2-f91d8ca50baf | Windows Antivirus | 5.00 |
3986ccb1-0890-451b-b819-e48b5b83ccab | Mac Antivirus | 7.00 |
9ea98956-7651-42e8-a704-a55acb55ea1d | Cloudberry | 3.00 |
f8bb1483-2e08-49ea-a506-c726cd0a2d6c | PSA | 2.00 |
73b27887-4da7-451f-bb91-c9fd3989c89e | TeamViewer | 2.00 |
Default User:
username: admin
password: Pa$$word