-
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.
feat: initial work on Apache HttpClient
- Loading branch information
Showing
2 changed files
with
209 additions
and
0 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,85 @@ | ||
plugins { | ||
`java-library` | ||
`maven-publish` | ||
signing | ||
id("com.diffplug.spotless") | ||
id("com.gradleup.nmcp") | ||
} | ||
|
||
java { | ||
sourceCompatibility = JavaVersion.VERSION_11 | ||
targetCompatibility = JavaVersion.VERSION_11 | ||
|
||
withJavadocJar() | ||
withSourcesJar() | ||
} | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
api(platform(project(":twirp-bom"))) | ||
|
||
implementation(project(":twirp-common")) | ||
|
||
api("com.google.protobuf:protobuf-java") | ||
implementation("com.google.protobuf:protobuf-java-util") | ||
implementation("org.apache.httpcomponents:httpclient:4.5.14") | ||
} | ||
|
||
publishing { | ||
publications { | ||
create<MavenPublication>("maven") { | ||
groupId = project.group as String | ||
artifactId = project.name | ||
version = project.version as String | ||
|
||
from(components["java"]) | ||
|
||
pom { | ||
name = project.name | ||
description = "Twirp Unirest client." | ||
url = "https://github.com/ngyewch/protoc-gen-twirp-java" | ||
licenses { | ||
license { | ||
name = "MIT License" | ||
url = "https://github.com/ngyewch/protoc-gen-twirp-java/blob/main/LICENSE" | ||
} | ||
} | ||
scm { | ||
connection = "scm:git:git@github.com:ngyewch/protoc-gen-twirp-java.git" | ||
developerConnection = "scm:git:git@github.com:ngyewch/protoc-gen-twirp-java.git" | ||
url = "https://github.com/ngyewch/protoc-gen-twirp-java" | ||
} | ||
developers { | ||
developer { | ||
id.set("ngyewch") | ||
name.set("Nick Ng") | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
signing { | ||
useGpgCmd() | ||
sign(publishing.publications["maven"]) | ||
} | ||
|
||
spotless { | ||
java { | ||
googleJavaFormat("1.23.0").reflowLongStrings().skipJavadocFormatting() | ||
formatAnnotations() | ||
targetExclude("build/**") | ||
} | ||
} | ||
|
||
nmcp { | ||
publish("maven") { | ||
username = project.properties["mavenCentralUsername"] as String? | ||
password = project.properties["mavenCentralPassword"] as String? | ||
publicationType = "AUTOMATIC" | ||
} | ||
} |
124 changes: 124 additions & 0 deletions
124
...e-httpclient/src/main/java/io/github/ngyewch/twirp/httpclient/client/AbstractService.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,124 @@ | ||
package io.github.ngyewch.twirp.httpclient.client; | ||
|
||
import com.google.protobuf.InvalidProtocolBufferException; | ||
import com.google.protobuf.Message; | ||
import com.google.protobuf.util.JsonFormat; | ||
import io.github.ngyewch.twirp.*; | ||
import java.io.IOException; | ||
import java.net.URI; | ||
import org.apache.http.HttpEntity; | ||
import org.apache.http.HttpStatus; | ||
import org.apache.http.client.methods.CloseableHttpResponse; | ||
import org.apache.http.client.methods.HttpPost; | ||
import org.apache.http.entity.ByteArrayEntity; | ||
import org.apache.http.entity.ContentType; | ||
import org.apache.http.entity.StringEntity; | ||
import org.apache.http.impl.client.CloseableHttpClient; | ||
import org.apache.http.impl.client.HttpClients; | ||
import org.apache.http.util.EntityUtils; | ||
|
||
public abstract class AbstractService { | ||
public static final ContentType PROTOBUF_CONTENT_TYPE = | ||
ContentType.create("application/protobuf"); | ||
public static final ContentType JSON_CONTENT_TYPE = ContentType.create("application/json"); | ||
|
||
private final URI baseUri; | ||
private final CloseableHttpClient httpClient; | ||
private final ContentType contentType; | ||
|
||
protected AbstractService(String baseUri, ContentType contentType) { | ||
super(); | ||
|
||
this.baseUri = URI.create(baseUri); | ||
this.httpClient = HttpClients.createDefault(); | ||
this.contentType = contentType; | ||
} | ||
|
||
protected void doRequest(String path, Message input, Message.Builder outputBuilder) { | ||
final URI uri = baseUri.resolve(path); | ||
try { | ||
if (contentType == PROTOBUF_CONTENT_TYPE) { | ||
doProtobufRequest(uri, input, outputBuilder); | ||
} else if (contentType == JSON_CONTENT_TYPE) { | ||
doJsonRequest(uri, input, outputBuilder); | ||
} else { | ||
throw new IllegalArgumentException("unsupported content type"); | ||
} | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
private void doProtobufRequest(URI uri, Message input, Message.Builder outputBuilder) | ||
throws IOException { | ||
final HttpEntity requestBody = new ByteArrayEntity(input.toByteArray(), PROTOBUF_CONTENT_TYPE); | ||
final HttpPost request = new HttpPost(uri); | ||
request.setEntity(requestBody); | ||
try (final CloseableHttpResponse response = httpClient.execute(request)) { | ||
final HttpEntity responseBody = response.getEntity(); | ||
try { | ||
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { | ||
expectContentType(responseBody, Constants.PROTOBUF_CONTENT_TYPE); | ||
mergeProtobuf(outputBuilder, EntityUtils.toByteArray(responseBody)); | ||
} else { | ||
expectContentType(responseBody, Constants.JSON_CONTENT_TYPE); | ||
throw new TwirpException(TwirpError.fromJson(EntityUtils.toString(responseBody))); | ||
} | ||
} finally { | ||
EntityUtils.consume(responseBody); | ||
} | ||
} | ||
} | ||
|
||
private void doJsonRequest(URI uri, Message input, Message.Builder outputBuilder) | ||
throws IOException { | ||
final HttpEntity requestBody = | ||
new StringEntity(JsonFormat.printer().print(input), ContentType.APPLICATION_JSON); | ||
final HttpPost request = new HttpPost(uri); | ||
request.setEntity(requestBody); | ||
try (final CloseableHttpResponse response = httpClient.execute(request)) { | ||
final HttpEntity responseBody = response.getEntity(); | ||
try { | ||
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { | ||
expectContentType(responseBody, Constants.JSON_CONTENT_TYPE); | ||
mergeProtobufJson(outputBuilder, EntityUtils.toString(responseBody)); | ||
} else { | ||
expectContentType(responseBody, Constants.JSON_CONTENT_TYPE); | ||
throw new TwirpException(TwirpError.fromJson(EntityUtils.toString(responseBody))); | ||
} | ||
} finally { | ||
EntityUtils.consume(responseBody); | ||
} | ||
} | ||
} | ||
|
||
private void expectContentType(HttpEntity responseBody, String expectedContentType) { | ||
final String contentType = | ||
(responseBody.getContentType() != null) ? responseBody.getContentType().getValue() : null; | ||
if (contentType == null) { | ||
throw new TwirpException(TwirpErrorCode.INVALID_ARGUMENT, "content type not specified", null); | ||
} else if (!contentType.equals(expectedContentType)) { | ||
throw new TwirpException( | ||
TwirpErrorCode.INVALID_ARGUMENT, | ||
"unexpected content type", | ||
new Meta().set("Content-Type", contentType).get()); | ||
} | ||
} | ||
|
||
private Message.Builder mergeProtobufJson(Message.Builder messageBuilder, String json) { | ||
try { | ||
JsonFormat.parser().merge(json, messageBuilder); | ||
return messageBuilder; | ||
} catch (InvalidProtocolBufferException e) { | ||
throw new TwirpException(TwirpErrorCode.MALFORMED, e, true); | ||
} | ||
} | ||
|
||
private Message.Builder mergeProtobuf(Message.Builder messageBuilder, byte[] data) { | ||
try { | ||
return messageBuilder.mergeFrom(data); | ||
} catch (InvalidProtocolBufferException e) { | ||
throw new TwirpException(TwirpErrorCode.MALFORMED, e, true); | ||
} | ||
} | ||
} |