Skip to content

Commit

Permalink
CRUD App Env Details (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
bibekaryal86 authored Oct 16, 2024
1 parent 87c88b1 commit b3f2549
Show file tree
Hide file tree
Showing 29 changed files with 933 additions and 381 deletions.
12 changes: 0 additions & 12 deletions .github/dependabot.yml

This file was deleted.

75 changes: 0 additions & 75 deletions .github/workflows/codeql-analysis.yml

This file was deleted.

4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ RUN addgroup -S springdocker
RUN adduser -S springdocker -G springdocker
USER springdocker:springdocker
WORKDIR /app
COPY --from=build /app/build/libs/spring-service-skeleton.jar .
COPY --from=build /app/build/libs/env-service.jar .
EXPOSE 8080
ENTRYPOINT ["java","-jar", "spring-service-skeleton.jar"]
ENTRYPOINT ["java","-jar", "env-service.jar"]
# provide environment variables in docker-compose
118 changes: 71 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,47 +1,71 @@
# spring-service-skeleton

* This is a template Repository to create a new Spring Boot REST Service
* Things to update:
* Refactor the package name from `spring.service.skeleton.app` to as desired
* keep it 3 words if possible, eg: `xxx.xxx.xxx.app`
* `settings.gradle`
* `rootProject.name`
* `build.gradle`
* Add/Remove dependencies as necessary
* `springVersion`, and version in buildscript and plugin as necessary
* `archiveFileName` in `bootJar`
* `mainClass` in `application`
* gradle wrapper version as necessary
* `application.yml` as necessary
* at least need to replace `spring-service-skeleton` with application name
* `logback.xml` as necessary
* avoid LOG_FILE as much as possible, prefer console logging
* replace `spring-service-skeleton` with application name in `LOG_PATTERN` and `LOG_FILE`
* remove `traceId` and `spanId` if `spring-cloud-started-sleuth` is not used in `build.gradle`
* `Dockerfile` as necessary
* esp `JAR_FILE`, `COPY` and environment variables in `ENTRYPOINT`
* GCP configurations, in `gcp` folder as necessary
* esp `app-credentials.yaml` and `app-credentials_DUMMY.yaml`
* `README.md` i.e. this file to add the program's readme
* `.gitignore` if necessary
* Things to add:
* `DatasourceConfig` if using MONGO/JPA/JDBC
* See: `pets-database-layer` for MongoDB example
* https://github.com/bibekaryal86/pets-database-layer
* See: `health-data-java` for JPA example
* https://github.com/bibekaryal86/health-data-java
* For JDBC, only need to set `Datasource` from above examples
* `RestTemplateConfig` if using `RestTemplate`
* See: `pets-service-layer` for example
* https://github.com/bibekaryal86/pets-service-layer
* `SwaggerConfig` if using SwaggerUI
* See: `pets-service-layer` / `pets-database-layer` for example
* https://github.com/bibekaryal86/pets-service-layer
* https://github.com/bibekaryal86/pets-database-layer
* Also, will have to update `SecurityConfig` to allow SwaggerUI
* Things to remove:
* If not using cache
* Remove `CacheConfig` from config package
* Remove `spring-boot-starter-cache` dependency from `build.gradle`
* GitHub workflows
* Remove `dependabot.yml` in the new app until automated merge is figured out
# env-service

### Overview:

This is a Spring Boot-based utility application that interacts with a MongoDB database and provides an interface
for saving, retrieving, and deleting documents in MongoDB.
The documents that are saved represent runtime variables that can be consumed by other applications as and when needed.
A new MongoDb collection is created for each application, and the application name should be sent with each request.

### Features:

* Create: Persist data into a MongoDB collection. A new collection is created for each new application
* Read: Fetch stored documents from the corresponding MongoDB collection
* Update: Update functionality is not provided. If a document needs to be updated, it has to be recreated after deleting first.
* Delete: Delete document from a MongoDB collection

### Technologies:

* Java
* Spring Boot
* Gradle
* MongoDB
* JUnit
* OpenApi

### Setup and Installation:
* git clone https://github.com/bibekaryal86/env-service.git
* Navigate to the project directory
* `cd env-service`
* Build the project
* `./gradlew clean build`
* Run the application
* The application requires the following environment variables to be provided at runtime:
* AUTH_USR: Username of Basic Authentication implemented in the application
* AUTH_PWD: Password of Basic Authentication implemented in the application
* MONGO_APP: MongoDB Application name, required/found in MongoDB connection string
* MONGO_DB: MongoDB Database name, required/found in MongoDB connection string
* MONGO_USR: MongoDB Database user name, required/found in MongoDB connection string
* MONGO_PWD: MongoDB Database user password, required/found in MongoDB connection string
* SPRING_PROFILES_ACTIVE: development or production or any, this is optional but best to set
* Profile `springboottest` is used when running JUnit tests
* There are matching `springProfile` configuration in `logback.xml`
* Run command:
* java -jar -DAUTH_USR=some_username -DAUTH_PWD=some_password -DMONGO_APP=some_app -DMONGO_DB=some_database -DMONGO_USR=another_user -DMONGO_PWD=another_password SPRING_PROFILES_ACTIVE=production app/build/libs/env-service.jar

### API Endpoints:
* GET /tests/ping
* Returns `{"ping": "successful"}`, no other functionalities
* POST /api/v1/{appName}
* Create a document in collection for `appName`
* If a collection doesn't exist for the `appName`, collection is created and then the document in the collection
* Constraints:
* There can not be two documents with same `name` attribute in a collection
* A document must have `name` and one of either `stringValue`, `listValue` or `mapValue` field populated
* GET /api/v1/{appName}
* Retrieve all documents in collection for `appName`
* PUT /api/v1/{appName}/{id}
* Update is not allowed, this returns `Method Not Allowed` response
* DELETE /api/v1/{appName}/{envDetailsName}
* Delete a document in collection for `appName` where `envDetailsName` matches `name` attribute in the document

### Deployment
This is currently deployed to Google Cloud Platform App Engine's Free Tier:
* https://envsvc.appspot.com/envsvc/tests/ping
* Deployment instructions:
* Build the project: `./gradlew clean build`
* Copy the generated jar file to the `gcp` library: `cp app/build/libs/env-service.jar gcp`
* Configure `app-credentials.yaml`
* copy `app-credentials_DUMMY.yaml` and update with actual values
* Deploy to app engine: `gcloud app deploy app.yaml`
* Best to start the process from `gcloud init` to select correct gcp project to deploy to
38 changes: 9 additions & 29 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ repositories {
}

bootJar {
archiveFileName = 'spring-service-skeleton.jar'
archiveFileName = 'env-service.jar'
}

dependencies {
Expand All @@ -37,47 +37,27 @@ dependencies {
implementation "org.springframework.boot:spring-boot-starter-actuator:$springVersion"
implementation "org.springframework.boot:spring-boot-starter-web:$springVersion"
implementation "org.springframework.boot:spring-boot-starter-security:$springVersion"
implementation "org.springframework.boot:spring-boot-starter-cache:$springVersion"

implementation 'ch.qos.logback:logback-classic:1.5.10'

// FOR ClassNotFoundException javax.xml.bind.JAXBException
implementation 'javax.xml.bind:jaxb-api:2.3.1'

// FOR REST TEMPLATE
implementation 'org.apache.httpcomponents.client5:httpclient5:5.4'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.0'

// IF USING JPA
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springVersion"

// IF USING JDBC
implementation "org.springframework.boot:spring-boot-starter-data-jdbc:$springVersion"

// IF USING MONGO
implementation "org.springframework.boot:spring-boot-starter-data-mongodb:$springVersion"
implementation "org.springframework.boot:spring-boot-starter-data-rest:$springVersion"

// IF USING SWAGGER
implementation 'ch.qos.logback:logback-classic:1.5.10'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0'

// IF USING APP IN A MICROSERVICES CLUSTER WITH GATEWAY, THIS WILL LOG TRACE/SPAN
implementation 'io.micrometer:micrometer-tracing-bridge-otel:1.3.4'

// FOR TESTING
testImplementation("org.springframework.boot:spring-boot-starter-test:$springVersion") {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'org.springframework.security:spring-security-test:6.3.3'
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.11.2'
testImplementation 'org.mockito:mockito-core:5.14.1'
}

// IF USING ELK STACK OR OTHER JSON LOGGING DRIVER
// ALSO UPDATE LOGBACK.XML
implementation 'net.logstash.logback:logstash-logback-encoder:8.0'
test {
useJUnitPlatform()
}

application {
mainClass = 'spring.service.skeleton.App'
mainClass = 'env.service.App'
}

configurations {
Expand Down
57 changes: 57 additions & 0 deletions app/src/main/java/env/service/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package env.service;

import static env.service.app.util.CommonUtils.getSystemEnvProperty;
import static env.service.app.util.ConstantUtils.AUTH_PWD;
import static env.service.app.util.ConstantUtils.AUTH_USR;
import static env.service.app.util.ConstantUtils.MONGO_APP;
import static env.service.app.util.ConstantUtils.MONGO_DB;
import static env.service.app.util.ConstantUtils.MONGO_PWD;
import static env.service.app.util.ConstantUtils.MONGO_USR;
import static env.service.app.util.ConstantUtils.SERVER_PORT;
import static java.util.Collections.singletonMap;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@Slf4j
@SpringBootApplication
public class App {

public static void main(final String[] args) {
log.info("Begin application initialization...");
validateEnvVarsInput();

SpringApplication app = new SpringApplication(App.class);
app.setDefaultProperties(
singletonMap("server.port", getSystemEnvProperty(SERVER_PORT, "8081")));
app.run(args);
log.info("End application initialization...");
}

private static void validateEnvVarsInput() {
boolean isEnvVarsMissing = getSystemEnvProperty(AUTH_USR, null) == null;
if (getSystemEnvProperty(AUTH_PWD, null) == null) {
isEnvVarsMissing = true;
}
if (getSystemEnvProperty(MONGO_APP, null) == null) {
isEnvVarsMissing = true;
}
if (getSystemEnvProperty(MONGO_DB, null) == null) {
isEnvVarsMissing = true;
}
if (getSystemEnvProperty(MONGO_USR, null) == null) {
isEnvVarsMissing = true;
}
if (getSystemEnvProperty(MONGO_PWD, null) == null) {
isEnvVarsMissing = true;
}
if (isEnvVarsMissing) {
throw new IllegalStateException(
"One or more required env variables are missing for initialization...");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package spring.service.skeleton.app.config;
package env.service.app.config;

import env.service.app.util.InterceptorUtilsLogging;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import spring.service.skeleton.app.util.InterceptorUtilsLogging;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(InterceptorRegistry registry) {
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(new InterceptorUtilsLogging());
}
}
Loading

0 comments on commit b3f2549

Please sign in to comment.