-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add services responsible for fetching data from GitHub API. Add domai…
…n classes. Add tests for same layer.
- Loading branch information
homer
committed
Jan 28, 2020
1 parent
d1edcc5
commit c64e3bf
Showing
19 changed files
with
927 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
HELP.md | ||
github.token | ||
.gradle | ||
build/ | ||
!gradle/wrapper/gradle-wrapper.jar | ||
!**/src/main/** | ||
!**/src/test/** | ||
|
||
### STS ### | ||
.apt_generated | ||
.classpath | ||
.factorypath | ||
.project | ||
.settings | ||
.springBeans | ||
.sts4-cache | ||
|
||
### IntelliJ IDEA ### | ||
.idea | ||
*.iws | ||
*.iml | ||
*.ipr | ||
out/ | ||
|
||
### NetBeans ### | ||
/nbproject/private/ | ||
/nbbuild/ | ||
/dist/ | ||
/nbdist/ | ||
/.nb-gradle/ | ||
|
||
### VS Code ### | ||
.vscode/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
lombok.anyConstructor.addConstructorProperties = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
src/main/java/com/gosiewski/contributorsjava/dto/incoming/ContributorRequestDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.gosiewski.contributorsjava.dto.incoming; | ||
|
||
import lombok.Value; | ||
|
||
@Value | ||
public final class ContributorRequestDto { | ||
private final String login; | ||
private final int contributions; | ||
} |
8 changes: 8 additions & 0 deletions
8
src/main/java/com/gosiewski/contributorsjava/dto/incoming/RepositoryRequestDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.gosiewski.contributorsjava.dto.incoming; | ||
|
||
import lombok.Value; | ||
|
||
@Value | ||
public final class RepositoryRequestDto { | ||
private String name; | ||
} |
9 changes: 9 additions & 0 deletions
9
src/main/java/com/gosiewski/contributorsjava/dto/outgoing/ContributorDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.gosiewski.contributorsjava.dto.outgoing; | ||
|
||
import lombok.Value; | ||
|
||
@Value | ||
public class ContributorDto { | ||
private String name; | ||
private int contributions; | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/com/gosiewski/contributorsjava/error/ApiCallError.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.gosiewski.contributorsjava.error; | ||
|
||
public final class ApiCallError extends Error { | ||
public ApiCallError() { | ||
super("External HTTP response was different than expected."); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/java/com/gosiewski/contributorsjava/error/Error.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.gosiewski.contributorsjava.error; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public abstract class Error { | ||
private final String reason; | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/com/gosiewski/contributorsjava/error/IllegalArgumentError.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.gosiewski.contributorsjava.error; | ||
|
||
public final class IllegalArgumentError extends Error { | ||
public IllegalArgumentError(String reason) { | ||
super(reason); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/com/gosiewski/contributorsjava/error/NotFoundError.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.gosiewski.contributorsjava.error; | ||
|
||
public final class NotFoundError extends Error { | ||
public NotFoundError() { | ||
super("Not found"); | ||
} | ||
} |
102 changes: 102 additions & 0 deletions
102
src/main/java/com/gosiewski/contributorsjava/service/GitHubAPIService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package com.gosiewski.contributorsjava.service; | ||
|
||
import com.gosiewski.contributorsjava.dto.incoming.ContributorRequestDto; | ||
import com.gosiewski.contributorsjava.dto.incoming.RepositoryRequestDto; | ||
import com.gosiewski.contributorsjava.error.ApiCallError; | ||
import com.gosiewski.contributorsjava.error.Error; | ||
import com.gosiewski.contributorsjava.error.IllegalArgumentError; | ||
import com.gosiewski.contributorsjava.service.domain.Contributor; | ||
import com.gosiewski.contributorsjava.service.domain.Repository; | ||
import io.vavr.collection.List; | ||
import io.vavr.collection.Seq; | ||
import io.vavr.control.Either; | ||
import lombok.RequiredArgsConstructor; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.util.ArrayList; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class GitHubAPIService { | ||
final static Logger logger = LoggerFactory.getLogger(GitHubAPIService.class); | ||
|
||
private final static String REPOS_URL = "https://api.github.com/orgs/%1$s/repos"; | ||
private final static String CONTRIBUTORS_URL = "https://api.github.com/repos/%1$s/%2$s/contributors"; | ||
|
||
private final HttpClient httpClient; | ||
|
||
final Either<Error, Seq<Repository>> getOrganizationRepos(final String organizationName) { | ||
if (organizationName.isBlank()) { | ||
return Either.left(new IllegalArgumentError("Organization name cannot be blank.")); | ||
} | ||
|
||
final String url = String.format(REPOS_URL, organizationName); | ||
|
||
return getFullGitHubResource(url, RepositoryRequestDto.class).map(this::mapRepositoryDtos); | ||
} | ||
|
||
final Either<Error, Seq<Contributor>> getRepoContributors(final String ownerName, | ||
final String repoName) { | ||
if (ownerName.isBlank() || repoName.isBlank()) { | ||
return Either.left(new IllegalArgumentError("Owner name or repo name cannot be blank.")); | ||
} | ||
|
||
final String url = String.format(CONTRIBUTORS_URL, ownerName, repoName); | ||
|
||
return getFullGitHubResource(url, ContributorRequestDto.class).map(this::mapContributorDtos); | ||
} | ||
|
||
private <T> Either<Error, Seq<T>> getFullGitHubResource(final String url, final Class<T> clazz) { | ||
Either<Error, ResponseEntity<java.util.List<T>>> result = httpClient.fetchFirstPage(url, clazz); | ||
|
||
if (result.isLeft()) { | ||
return Either.left(result.getLeft()); | ||
} | ||
|
||
ResponseEntity<java.util.List<T>> response = result.get(); | ||
|
||
if (response.getBody() == null) { | ||
logEmptyBodyError(response.toString()); | ||
|
||
return Either.left(new ApiCallError()); | ||
} | ||
|
||
final java.util.List<T> fullResult = new ArrayList<>(response.getBody()); | ||
|
||
while(httpClient.hasNextPage(response.getHeaders())) { | ||
result = httpClient.fetchNextPage(response, clazz); | ||
|
||
if (result.isLeft()) { | ||
return Either.left(result.getLeft()); | ||
} | ||
|
||
response = result.get(); | ||
|
||
if (response.getBody() == null) { | ||
logEmptyBodyError(response.toString()); | ||
|
||
return Either.left(new ApiCallError()); | ||
} | ||
|
||
fullResult.addAll(response.getBody()); | ||
} | ||
|
||
return Either.right(List.ofAll(fullResult)); | ||
} | ||
|
||
private Seq<Contributor> mapContributorDtos(final Seq<ContributorRequestDto> dtos) { | ||
return dtos.map(contributorDto -> new Contributor(contributorDto.getLogin(), contributorDto.getContributions())); | ||
} | ||
|
||
private Seq<Repository> mapRepositoryDtos(final Seq<RepositoryRequestDto> dtos) { | ||
return dtos.map(repositoryDto -> new Repository(repositoryDto.getName())); | ||
} | ||
|
||
private void logEmptyBodyError(final String response) { | ||
logger.error("GitHub responded with empty body:"); | ||
logger.error(response); | ||
} | ||
} |
Oops, something went wrong.