Santiago Russo
Santiago Russo

Reputation: 109

Configure API Host throught SpringBoot Profiles

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

Answers (2)

isudarsan
isudarsan

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

Ken Chan
Ken Chan

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

Related Questions