Skip to content

Commit

Permalink
Implementing swagger docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel committed Oct 14, 2021
1 parent 1571411 commit 62e46c7
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 39 deletions.
11 changes: 11 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<liquibase-hibernate5.version>3.10.2</liquibase-hibernate5.version>
<cucumber.version>6.11.0</cucumber.version>
<jacoco.line-coverage>0.80</jacoco.line-coverage>
<swagger.version>3.0.0</swagger.version>
</properties>
<dependencies>
<dependency>
Expand All @@ -45,6 +46,16 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import java.util.TimeZone;

@SpringBootApplication
@EnableScheduling
//@EnableScheduling
public class StockDataServiceApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@
import com.dpgrandslam.stockdataservice.domain.service.TenYearTreasuryYieldService;
import com.dpgrandslam.stockdataservice.domain.service.TrackedStockService;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.jni.Local;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

@Controller
@RequestMapping("/data")
Expand All @@ -37,11 +39,11 @@ public class StockDataServiceController {
@Autowired
private TenYearTreasuryYieldService treasuryYieldService;

@GetMapping("/option/{ticker}")
@GetMapping(value = "/option/{ticker}", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<List<OptionsChain>> getOptionsChain(@PathVariable(name = "ticker") String ticker,
@RequestParam(name = "expirationDate") Optional<String> expirationDate,
@RequestParam(name = "startDate") Optional<String> startDate,
@RequestParam(name = "endDate") Optional<String> endDate) throws OptionsChainLoadException {
@RequestParam(name = "expirationDate", required = false) Optional<String> expirationDate,
@RequestParam(name = "startDate", required = false) Optional<String> startDate,
@RequestParam(name = "endDate", required = false) Optional<String> endDate) throws OptionsChainLoadException {
log.info("Received request for options data with ticker: {}, expirationDate: {}, startDate: {}, and endDate: {}",
ticker, expirationDate.orElse(null), startDate.orElse(null), endDate.orElse(null));
List<OptionsChain> retVal = new ArrayList<>();
Expand All @@ -64,66 +66,66 @@ public ResponseEntity<List<OptionsChain>> getOptionsChain(@PathVariable(name = "
return ResponseEntity.ok(retVal);
}

@GetMapping("/option/{ticker}/all")
@GetMapping(value = "/option/{ticker}/all", produces = APPLICATION_JSON_VALUE)
@Transactional
public ResponseEntity<List<OptionsChain>> getFullOptionsChain(@PathVariable String ticker) throws OptionsChainLoadException {
return ResponseEntity.ok(optionsChainLoadService.loadFullOptionsChainWithAllData(ticker));
}

@GetMapping("/stock/{ticker}")
@GetMapping(value = "/stock/{ticker}", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<List<EndOfDayStockData>> getEndOfDayStockData(@PathVariable String ticker,
Optional<String> startDate,
Optional<String> endDate) {
@RequestParam(required = false) Optional<String> startDate,
@RequestParam(required = false) Optional<String> endDate) {
if (startDate.isEmpty() && endDate.isEmpty()) {
return ResponseEntity.ok(stockDataLoadService.getMostRecentEndOfDayStockData(ticker));
}
return ResponseEntity.ok(stockDataLoadService.getEndOfDayStockData(ticker, startDate.map(LocalDate::parse).orElse(LocalDate.MIN),
endDate.map(LocalDate::parse).orElse(LocalDate.now())));
}

@GetMapping("/stock/{ticker}/live")
@GetMapping(value = "/stock/{ticker}/live", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<LiveStockData> getLiveStockData(@PathVariable(name = "ticker") String ticker) {
return ResponseEntity.ok(stockDataLoadService.getLiveStockData(ticker));
}

@GetMapping("/stock/search")
@GetMapping(value = "/stock/search", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<List<? extends StockSearchResult>> searchStock(@RequestParam(name = "q") String query) {
return ResponseEntity.ok(stockDataLoadService.searchStock(query));
}

@GetMapping("/tracked")
@GetMapping(value = "/tracked", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<List<TrackedStock>> getTrackedStocks(@RequestParam(name = "activeOnly", required = false, defaultValue = "true") boolean activeOnly) {
return ResponseEntity.ok(trackedStockService.getAllTrackedStocks(activeOnly));
}

@PutMapping("/tracked/active")
public ResponseEntity<Map<String, Object>> updateTrackedStocksActive(@RequestBody Map<String, Boolean> body) {
Map<String, Object> response = new HashMap<>();
Map<String, String> failedUpdates = new HashMap<>();
body.forEach((key, value) -> {
@PutMapping(value = "/tracked/active", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<TrackedStockUpdateResponse> updateTrackedStocksActive(@RequestBody List<TrackedStockUpdateRequest> body) {
TrackedStockUpdateResponse response = new TrackedStockUpdateResponse();
List<TrackedStockUpdateResponse.FailedUpdate> failedUpdates = new ArrayList<>();
body.forEach((request) -> {
try {
trackedStockService.setTrackedStockActive(key, value);
trackedStockService.setTrackedStockActive(request.getTicker(), request.getTracked());
} catch (Exception e) {
failedUpdates.put(key, "Could not update status of tracked stock " + key + ". Reason: " + e.getMessage());
failedUpdates.add(new TrackedStockUpdateResponse.FailedUpdate(request.getTicker(), "Could not update status of tracked stock " + request.getTicker() + ". Reason: " + e.getMessage()));
}
});
if (failedUpdates.isEmpty()) {
response.put("status", "success");
response.setStatus("success");
} else {
response.put("status", "has_failures");
response.put("failed", failedUpdates);
response.setStatus("has_failures");
response.setFailedUpdates(failedUpdates);
}
return ResponseEntity.ok(response);
}

@PostMapping(value = "/tracked", consumes = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(value = "/tracked", consumes = APPLICATION_JSON_VALUE)
public ResponseEntity addTrackedStocks(@RequestBody List<String> tickers) {
trackedStockService.addTrackedStocks(tickers);
return ResponseEntity.status(HttpStatus.CREATED).build();
}

@GetMapping("/treasury-yield")
public ResponseEntity<YahooFinanceTenYearTreasuryYield> getTreasuryYield(@RequestParam Optional<String> date) {
@GetMapping(value = "/treasury-yield", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<YahooFinanceTenYearTreasuryYield> getTreasuryYield(@RequestParam(required = false) Optional<String> date) {
return ResponseEntity.ok(treasuryYieldService.getTreasuryYieldForDate(date.map(LocalDate::parse)
.orElse(LocalDate.now())));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.dpgrandslam.stockdataservice.domain.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

@Configuration
public class SpringFoxConfig {

@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.dpgrandslam.stockdataservice.adapter.api"))
.paths(PathSelectors.any())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.dpgrandslam.stockdataservice.domain.model.stock;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class TrackedStockUpdateRequest {
private String ticker;
private Boolean tracked;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.dpgrandslam.stockdataservice.domain.model.stock;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class TrackedStockUpdateResponse {
private String status;
private List<FailedUpdate> failedUpdates;

@Data

@AllArgsConstructor
@NoArgsConstructor
public static class FailedUpdate {
private String ticker;
private String message;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
import com.dpgrandslam.stockdataservice.domain.error.OptionsChainLoadException;
import com.dpgrandslam.stockdataservice.domain.model.options.Option;
import com.dpgrandslam.stockdataservice.domain.model.options.OptionsChain;
import com.dpgrandslam.stockdataservice.domain.model.stock.EndOfDayStockData;
import com.dpgrandslam.stockdataservice.domain.model.stock.LiveStockData;
import com.dpgrandslam.stockdataservice.domain.model.stock.StockSearchResult;
import com.dpgrandslam.stockdataservice.domain.model.stock.TrackedStock;
import com.dpgrandslam.stockdataservice.domain.model.stock.*;
import com.dpgrandslam.stockdataservice.domain.model.tiingo.TiingoStockSearchResponse;
import com.dpgrandslam.stockdataservice.domain.service.OptionsChainLoadService;
import com.dpgrandslam.stockdataservice.domain.service.StockDataLoadService;
Expand Down Expand Up @@ -76,22 +73,23 @@ public void testGetTrackedStocks_all_returnsAll() {

@Test
public void testUpdateTrackedStocksActive() {
Map<String, Boolean> request = new HashMap<>();
request.put("TEST1", true);
request.put("TEST2", false);
request.put("TEST3", true);
List<TrackedStockUpdateRequest> request = new ArrayList<>();

request.add(new TrackedStockUpdateRequest("TEST1", true));
request.add(new TrackedStockUpdateRequest("TEST2", false));
request.add(new TrackedStockUpdateRequest("TEST3", true));

doNothing().doNothing().doThrow(new EntityNotFoundException("Not Found")).when(trackedStockService).setTrackedStockActive(anyString(), anyBoolean());

ResponseEntity<Map<String, Object>> response = subject.updateTrackedStocksActive(request);
ResponseEntity<TrackedStockUpdateResponse> response = subject.updateTrackedStocksActive(request);

verify(trackedStockService ,times(1)).setTrackedStockActive(eq("TEST1"), eq(true));
verify(trackedStockService, times(1)).setTrackedStockActive(eq("TEST2"), eq(false));
verify(trackedStockService, times(1)).setTrackedStockActive(eq("TEST3"), eq(true));

assertTrue(response.getStatusCode().is2xxSuccessful());
assertEquals("has_failures", response.getBody().get("status"));
assertEquals(1, ((Map<String, String>)response.getBody().get("failed")).size());
assertEquals("has_failures", response.getBody().getStatus());
assertEquals(1, response.getBody().getFailedUpdates().size());
}

@Test
Expand Down

0 comments on commit 62e46c7

Please sign in to comment.