A native (!) backend REST server of Fun7's fictional services, written in Java.
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2022-07-25 13:12:19,813 INFO [io.quarkus] (main) fun7-services 1.0.0-SNAPSHOT native started in 0.019s.
- Quarkus framework for development.
- with Jib for containerisation
- MongoDB for data management.
- Cloud Run for serverless computing.
- GitHub Actions for continuous integration.
TL;DR:
curl -s https://raw.githubusercontent.com/ccjmne/fun7-services/master/docker-compose.yml > docker-compose.yml
docker-compose up --detach
curl -i 'http://localhost:8080?cc=SI&userId=123456789012345678901234&timezone=Europe/Ljubljana'git clone https://github.com/ccjmne/fun7-services- or
curl -s https://raw.githubusercontent.com/ccjmne/fun7-services/master/docker-compose.yml > docker-compose.yml
- or
- Edit docker-compose.yml to tweak the environment variables
- notably,
ADPARTNER_URL,ADPARTNER_USERNAMEandADPARTNER_PASSWORD
- notably,
docker-compose up- Query it with your browser
- by default, you can access the user administration with
admin:pwd.
- by default, you can access the user administration with
Ctrl-Cdocker-compose down
- Query the Cloud Run endpoint where it is (temporarily) hosted:
https://fun7-jsppj7p4zq-od.a.run.app- this service actually does query Fun7's "real" ad partner
- you'll likely experience some ~0.040s delay (!) the first time, because Cloud Run will need to start up the server :)
This application exposes two endpoints:
| Where | What | Requires Auth |
|---|---|---|
/ |
Services Availability | ❌ |
/users |
User Administration | ✔ |
| Method | Path Params | What |
|---|---|---|
GET |
/ |
List all users |
GET |
/{userId} |
Retrieve a specific user's data |
DELETE |
/{userId} |
Delete a specific user |
| Method | Path Params | What |
|---|---|---|
GET |
/ |
Check availability of Fun7's services |
| Query Param | Meaning | Format | Required |
|---|---|---|---|
userId |
User unique ID | 24 hexadecimal characters e.g.: 123456789012345678901234 |
✔ |
cc |
User country code | ISO 3166-1 alpha-2 or -3 e.g.: SI |
✔ |
timezone |
User time zone | "IANA Time Zones" e.g.: Europe/Ljubljana |
❌ |
| Name | Meaning |
|---|---|
USERSUPPORT_TZ |
Time zone to consider for user support availability e.g.: Europe/Ljubljana |
USERSUPPORT_FROM |
Start time for the live support e.g.: 09:00 |
USERSUPPORT_TO |
End time for the live support e.g.: 15:00 |
ADPARTNER_URL |
URL queried to check support for ads by the partner e.g.: https://postman-echo.com/get |
ADPARTNER_USERNAME |
Username to authenticate query to ad partner e.g.: user |
ADPARTNER_PASSWORD |
Password to authenticate query to ad partner e.g.: pass |
MULTIPLAYER_COUNTRY |
Country where multiplayer is enabled e.g.: US |
MULTIPLAYER_MINCHECKINS |
The minimum amount of "check-ins" that constitutes a veteran player e.g.: 5 |
MONGO_URL |
The supporting database connection string e.g.: mongodb://db:27017 |
MONGO_DB |
The DB name it uses e.g.: users |
ADMIN_PASSWORD |
The password for the admin account that can access /userse.g.: pwd |
-
A user in the database has 3 properties:
id: their unique identifiercountry: the code of the country they last "checked in" fromapiCalls: the number of times they "checked in"
-
A user therefore looks like this:
{
"id": "12345678901234567890abcd",
"country": "SI",
"apiCalls": 22
}-
The
timezonequery parameter supplied by the user is discarded and serves no purpose// TODO:maybe at least store it in the database?
-
Users are created/updated in the database ever time they (succesfully) query
GET / -
The
/usersendpoint isn't publicly accessible and requires authentication- by default, set up w/ basic authentication against an embedded security realm
-
All input fields (query and path parameters) are parsed and validated before any "business" method is invoked
-
All errors due to bad requests (invalid input field, no match for supplied user id, etc) yield a
4xx-family answerNOT_FOUNDfor unmatched user idBAD_REQUESTfor the rest
-
Additionally, all error responses are normalised in the form:
{ "error": "invalid user id: should be 24 hexadecimal characters" } -
When the Ad Partner's request handler fails...
- with
5xx-family (internal server error)- log that with a
WARNINGseverity - carry on and assume ads aren't available
- log that with a
- with
4xx-family (bad request)- log that with a
ERRORseverity - yield a
500to the client, with an informative, normalised response body (see above)
- log that with a
- with
-
If the user support is configured to be available from
09:00to15:00...- in a pedantic world, it would become available at
09:00and stay so until15:00, where it would become unavailable - in reality, it makes sense that one would expect the range to be inclusive at both ends
- therefore, also return
enabledduring that one extra millisecond at15:00(until15:00:00.001)
- therefore, also return
- in a pedantic world, it would become available at
-
The relevant configuration entries are mapped to environment variables that match
[A-Z_]+- ... because Google Cloud's Kubernetes Engine doesn't accept
dotdash-style.environment-vars - ... despite Kubernetes itself being fine with it. Maybe it's just GKE's Web interface that doesn't play nice.
- actually, I can't set the minimum number of pods to be
0either - ... despite Kubernetes allowing it
- (I read in some GitHub issue that GKE also did, so maybe the culprit really is only their Web interface)
- actually, I can't set the minimum number of pods to be
- ... because Google Cloud's Kubernetes Engine doesn't accept
-
Integration testing isn't my forte
GPL-3.0
You may copy, distribute and modify the software as long as you track changes/dates in source files. Any modifications to or software including (via compiler) GPL-licensed code must also be made available under the GPL along with build & install instructions.
Refer to the LICENSE file for more details.
There is nothing more below but the useful parts of Quarkus' starter project's README.
You can run your application in dev mode that enables live coding using:
./mvnw compile quarkus:devThe application can be packaged using:
./mvnw packageIt produces the quarkus-run.jar file in the target/quarkus-app/ directory.
Be aware that it’s not an über-jar as the dependencies are copied into the target/quarkus-app/lib/ directory.
The application is now runnable using java -jar target/quarkus-app/quarkus-run.jar.
If you want to build an über-jar, execute the following command:
./mvnw package -Dquarkus.package.type=uber-jarThe application, packaged as an über-jar, is now runnable using java -jar target/*-runner.jar.
You can create a native executable using:
./mvnw package -PnativeOr, if you don't have GraalVM installed, you can run the native executable build in a container using:
./mvnw package -Pnative -Dquarkus.native.container-build=trueYou can then execute your native executable with: ./target/fun7-services-1.0.0-SNAPSHOT-runner