Reputation: 109
I am using SpringBoot, Java and Gradle for my project. My API connects to a Database configured through spring properties but also depends on an external API Rest for some data retrival.
My question is is there a way to configure the external API host and secret using spring properties? Which properties should i use? Is there a way to create custom properties?
## application.yml
---
spring:
profiles: dev
datasource:
platform: postgres
url:
jdbc:postgresql://${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME}
username: ${DATABASE_USER}
password: ${DATABASE_PASSWORD}
driverClassName: org.postgresql.Driver
initialize: true
liquibase:
change-log: classpath:db/changelog-master.xml
Upvotes: 0
Views: 264
Reputation: 477
You can safely adapt the below approach , in yml
file configure all secrets along with the external API endpoint.If you want to hide secrets further use Spring Vault
which used for storing and revoking secrets.
https://projects.spring.io/spring-vault/
security:
basic:
enabled: ${env.security.basic.enabled:false}
management:
security:
enabled: ${env.management.security.enabled:false}
apiUsername: apiUser
apiPassword: apiPassword
apiUrl: http://external-rest-api/RESTAdapter
dbUsername: dbUsername
dbPassword: dbPassword
dbServerUrl: jdbc:jtds:sqlserver://localhost:1433;
dbDriverClass: net.sourceforge.jtds.jdbc.Driver
dbServerDialect: org.hibernate.dialect.SQLServerDialect
dbName: databaseName=dbName;
---
spring:
profiles: Prod
dbDriverClass: net.sourceforge.jtds.jdbc.Driver
dbServerDialect: org.hibernate.dialect.SQLServerDialect
dbName: databaseName=prodDBName;
Write a service starter to spin up the service by taking the properties from the yml file.
@Configuration
@EnableJpaRepositories("com.dao")
public class ServiceConfig {
/**
* The meta data bean consisting of properties read from the yaml
* configuration file.
*/
@Value("${apiUsername}")
String apiUsername;
@Value("${apiPassword}")
String apiPassword;
@Value("${apiUrl}")
String apiUrl;
@Value("${dbUsername}")
String dbUsername;
@Value("${dbPassword}")
String dbPassword;
@Value("${dbServerUrl}")
String dbServerUrl;
@Value("${dbDriverClass}")
String dbDriverClass;
@Value("${dbServerDialect}")
String dbServerDialect;
@Value("${dbName}")
String dbName;
/**
* Creates and returns a bean of RestClientSapUtil.
*
* @return RestClientApiUtil bean
*/
@Bean(name = "restClientApiUtil")
public RestClientApiUtil getRestClientApiUtil() {
return new RestClientApiUtil(apiUsername, apiPassword, apiUrl);
}
@Bean(name = "datasource")
public DriverManagerDataSource getDriverManagerDataSource() {
DriverManagerDataSource driverManagerDataSource =
new DriverManagerDataSource();
driverManagerDataSource.setUsername(dbUsername);
driverManagerDataSource.setPassword(dbPassword);
driverManagerDataSource.setUrl(dbServerUrl + dbName);
driverManagerDataSource.setDriverClassName(dbDriverClass);
return driverManagerDataSource;
}
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean getLocalContainerEntityManagerFactoryBean() {
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean =
new LocalContainerEntityManagerFactoryBean();
HibernateJpaVendorAdapter jpaVendorAdapter =
new HibernateJpaVendorAdapter();
jpaVendorAdapter.setShowSql(true);
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setDatabasePlatform(dbServerDialect);
localContainerEntityManagerFactoryBean
.setJpaVendorAdapter(jpaVendorAdapter);
localContainerEntityManagerFactoryBean
.setDataSource(getDriverManagerDataSource());
localContainerEntityManagerFactoryBean
.setPackagesToScan("com.model");
return localContainerEntityManagerFactoryBean;
}
@Bean(name = "transactionManager")
public JpaTransactionManager getJpaTransactionManager(
EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
Finally you can build a utility class which talks to the external API interface, you can think of something similar below.
/**
* Provides methods for making requests to the API interface.
*
*
*/
public class RestClientApiUtil {
public RestClientApiUtil() {
}
private String apiUsername;
/**
* The password for accessing the external API interface.
*/
private String apiPassword;
/**
* The base URL for accessing the external API interface.
*/
private String apiUrl;
public RestClientApiUtil(String apiUsername,
String apiPassword, String apiUrl) {
this.apiUsername = apiUsername;
this.apiPassword = apiPassword;
this.apiUrl = apiUrl;
}
/**
* Makes a call to the external API interface and returns the response received.
* @param requestData the request data to attach in the request body
* @param endpoint the specific endpoint to make a request to
* @param clazz the class in which the response is expected
* @return Object
* @throws Exception
*/
public <T> T callService(Object requestData, String endpoint, Class<T> clazz)
throws TechnicalException {
RestTemplate restTemplate = null;
ResponseEntity<?> responseEntity = null;
String webServiceUrl = "";
HttpEntity<Object> requestBody = null;
try {
webServiceUrl = formServiceUrl(this.apiUrl, endpoint);
requestBody = createRequestBody(requestData);
restTemplate = new RestTemplate();
responseEntity = restTemplate.exchange(webServiceUrl, HttpMethod.POST, requestBody, clazz);
return clazz.cast(responseEntity.getBody());
} catch (Exception e) {
throw new Exception(e);
}
}
}
I hope this answer make some sense, if you have any further questions do let me know. Cheers !
Upvotes: 1
Reputation: 90467
Yes.The easiest way is just define any properties name you like in application.yml
:
api:
url: http://api.com/blablba/
password: fooPassword
Then use @Value
to inject these values into the API client bean:
@Component
public class ApiClient {
@Value("${api.url}")
private String url;
@Value("${api.password}")
private String password;
}
Upvotes: 1