Framework and build tools
For this project I chose to use Spring Boot alongside Gradle.
Purpose
Small assignment to assess your capacity to execute a specific request
It is taking into account some of the software engineering aspects beyond programming, like (non-exhaustive list):
-
Packaging
-
Layering
-
Error management
-
Documentation
-
Deployment aspects
-
Testing
This is a contrived example, especially designed to make the candidates exercise a deeper knowledge of the framework, going beyond simple tutorials that can be found online.
Credits (Purpose section) : B2Boost
Api documentation
In the following document you will find a simple documentation of the API. Most of the following sections have been generated with Spring Rest Docs.
The partner resource
Field | Type | Semantics | Example |
---|---|---|---|
id |
long |
The database id of the partner |
1 |
name |
string |
"The name of the partner" |
"B2Boost" |
reference |
string |
The unique reference of the partner |
"xxxxx" |
locale |
string |
A valid Locale of the partner |
"en_BE" |
expirationTime |
string |
The ISO-8601 UTC date time when the partner is going to expire |
"2022-11-24 17:46:00+01:00" |
Accessing all the partners GET endpoint
A GET
request is used to access all the partners read.
Request structure
GET /partners HTTP/1.1
Host: localhost:8080
Example response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1359
{
"content": [
{
"id": 1,
"name": "B2boost",
"reference": "FYI1",
"locale": "en_BE",
"expirationTime": "2022-11-24 17:46:00+01"
},
{
"id": 2,
"name": "Proximus",
"reference": "FYI2",
"locale": "en_BE",
"expirationTime": "2022-11-24 17:46:00+01"
},
// more json elements...
{
"id": 10,
"name": "Cisco",
"reference": "FYI10",
"locale": "en_US",
"expirationTime": "2022-11-24 17:46:00-04"
}
],
"pageable": {
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"offset": 0,
"pageNumber": 0,
"pageSize": 10,
"paged": true,
"unpaged": false
},
"totalPages": 2,
"totalElements": 12,
"last": false,
"size": 10,
"number": 0,
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"first": true,
"numberOfElements": 10,
"empty": false
}
Note
|
response body within content json array and pagination infos within pageable json object |
CURL request
$ curl 'http://localhost:8080/partners' -i -X GET
Pagination parameters
Parameter | Description |
---|---|
|
offset in the resultset to paginate to (default value is 0) |
|
Window pagination size (default value is 10) |
Exemple CURL request with pagination parameters
$ curl --location --request GET 'http://localhost:8080/partners?from=0&size=4'
Accessing the partner GET endpoint
A GET
request is used to access the partner read.
Request structure
GET /partner/1 HTTP/1.1
Host: localhost:8080
Path Parameters
Parameter | Description |
---|---|
|
id of partner to be searched |
Example response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 129
{
"id" : 1,
"name" : "B2boost",
"reference" : "FYI1",
"locale" : "en_BE",
"expirationTime" : "2022-11-24 17:46:00+01"
}
CURL request
$ curl 'http://localhost:8080/partner/1' -i -X GET
Example GET request with errors
Example with invalid value for id
$ curl --location --request GET 'http://localhost:8080/partner/-1'
Response
{
"code": 500,
"message": "getPartnerById.Id: must be greater than or equal to 1"
}
Note
|
The Min value for id is 1 |
Example partner not found
$ curl --location --request GET 'http://localhost:8080/partner/3000'
Response
{
"code": 404,
"message": "Partner with id 3000 not found!"
}
Accessing the partner POST endpoint
A POST
request is used to add a partner resource.
Request structure
POST /partner HTTP/1.1
Content-Type: application/json
Content-Length: 117
Host: localhost:8080
{
"reference" : "FYI25",
"expirationTime" : "2013-10-03T12:18:46+01:00",
"name" : "UPS",
"locale" : "en_BE"
}
Example response
HTTP/1.1 201 Created
Content-Type: application/json
Content-Length: 130
{
"id" : 13,
"name" : "UPS",
"reference" : "FYI25",
"locale" : "en_BE",
"expirationTime" : "2013-10-03T12:18:46+01:00"
}
CURL request
$ curl 'http://localhost:8080/partner' -i -X POST \
-H 'Content-Type: application/json' \
-d '{
"reference" : "FYI25",
"expirationTime" : "2013-10-03T12:18:46+01:00",
"name" : "UPS",
"locale" : "en_BE"
}'
Example POST request with errors
Example with error on create with wrong date format
$ curl --location --request POST 'http://localhost:8080/partner' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "UPS",
"reference": "FYI15",
"locale": "en_BE",
"expirationTime": "2017-10-03T12:18:46"
}'
Response
{
"code": 400,
"message": "Date 2017-10-03T12:18:46 is an invalid ISO-8601 UTC date time! Should be something like 2017-10-03T12:18:46+00:00"
}
Note
|
Here the UTC timezone is missing |
Example with error on create with invalid locale
$ curl --location --request POST 'http://localhost:8080/partner' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "UPS",
"reference": "FYI15",
"locale": "en_BEE",
"expirationTime": "2017-10-03T12:18:46+08:00"
}'
Response
{
"code": 400,
"message": "Locale en_BEE is an invalid Locale!"
}
Note
|
Here the locale should be en_BE |
Accessing the partner PUT endpoint
A PUT
request is used to update a partner resource.
Request structure
PUT /partner/3 HTTP/1.1
Content-Type: application/json
Content-Length: 97
Host: localhost:8080
{"reference":"FYI255","expirationTime":"2022-05-23T12:18:46+01:00","name":"DHL","locale":"de_DE"}
Example response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 104
{"id":3,"name":"DHL","reference":"FYI255","locale":"de_DE","expirationTime":"2022-05-23T12:18:46+01:00"}
CURL request
$ curl 'http://localhost:8080/partner/3' -i -X PUT \
-H 'Content-Type: application/json' \
-d '{"reference":"FYI255","expirationTime":"2022-05-23T12:18:46+01:00","name":"DHL","locale":"de_DE"}'
Example PUT request with errors
The errors for validating locale and date are the same between PUT and POST
Example with error on update with not unique reference
$ curl --location --request PUT 'http://localhost:8080/partner/1' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "UPS",
"reference": "FYI5",
"locale": "en_US",
"expirationTime": "2022-05-23T12:18:46-05:00"
}'
Response
{
"code": 500,
"message": "could not execute statement; SQL [n/a]; constraint [\"PUBLIC.CONSTRAINT_INDEX_7 ON PUBLIC.PARTNERS(REF) VALUES 5\"; SQL statement:\nupdate partners set expires=?, locale=?, company_name=?, ref=? where id=? [23505-200]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement"
}
Note
|
The reference attribute is configured to be a unique identifier for the partner |
Example with error on update with partner not found
$ curl --location --request PUT 'http://localhost:8080/partner/4000' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "UPS",
"reference": "FYI50",
"locale": "en_US",
"expirationTime": "2022-05-23T12:18:46-05:00"
}'
Response
{
"code": 404,
"message": "Partner with id 4000 not found!"
}
Accessing the partner DELETE endpoint
A DELETE
request is used to delete the partner.
Request structure
DELETE /partner/2 HTTP/1.1
Host: localhost:8080
Path Parameters
Parameter | Description |
---|---|
|
The id of the partner to delete |
Example response
HTTP/1.1 200 OK
CURL request
$ curl 'http://localhost:8080/partner/2' -i -X DELETE
Example DELETE request with errors
Example with error on update with with partner not found
$ curl --location --request DELETE 'http://localhost:8080/partner/2000'
Response
{
"code": 404,
"message": "Partner with id 2000 not found!"
}
Accessing the health check endpoint
$ curl --location --request GET 'http://localhost:8080/health'
Response
{
"status": "UP",
"components": {
"db": {
"status": "UP",
"details": {
"database": "H2",
"validationQuery": "isValid()"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 250438021120,
"free": 10172166144,
"threshold": 10485760,
"exists": true
}
},
"ping": {
"status": "UP"
}
}
}
Note
|
For security purpose you can display less by changing management.endpoint.health.show-details=always to never in application.properties
|
Useful commands
Assuming you are using a bash cli
Run the app in dev env
./gradlew bootRun
Run the test suite with gradle
./gradlew test
Prepare the jar archive with gradle for deployment
./gradlew clean bootJar
Note
|
Path of the output is build/libs/api-spring-gradle-b2boost-0.0.1-SNAPSHOT.jar
|