diff --git a/typescript-service-generator-core/src/main/java/com/palantir/code/ts/generator/ServiceClassParser.java b/typescript-service-generator-core/src/main/java/com/palantir/code/ts/generator/ServiceClassParser.java index 2d70311..61c795c 100644 --- a/typescript-service-generator-core/src/main/java/com/palantir/code/ts/generator/ServiceClassParser.java +++ b/typescript-service-generator-core/src/main/java/com/palantir/code/ts/generator/ServiceClassParser.java @@ -22,6 +22,7 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import org.apache.commons.lang3.reflect.MethodUtils; @@ -125,7 +126,18 @@ private static List computeEndpointModels(Set endp if (consumes.value().length > 1) { throw new IllegalArgumentException("Don't know how to handle an endpoint with multiple consume types"); } - ret.endpointMediaType(consumes.value()[0]); + if (consumes.value().length == 1) { + ret.endpointRequestMediaType(consumes.value()[0]); + } + } + Produces produces = endpoint.getAnnotation(Produces.class); + if (produces != null) { + if (produces.value().length > 1) { + throw new IllegalArgumentException("Don't know how to handle an endpoint with multiple produce types"); + } + if (produces.value().length == 1) { + ret.endpointResponseMediaType(produces.value()[0]); + } } List, Annotation>> annotationList = getParamterAnnotationMaps(endpoint); diff --git a/typescript-service-generator-core/src/main/java/com/palantir/code/ts/generator/ServiceEmitter.java b/typescript-service-generator-core/src/main/java/com/palantir/code/ts/generator/ServiceEmitter.java index 6597862..96c41f7 100644 --- a/typescript-service-generator-core/src/main/java/com/palantir/code/ts/generator/ServiceEmitter.java +++ b/typescript-service-generator-core/src/main/java/com/palantir/code/ts/generator/ServiceEmitter.java @@ -12,6 +12,8 @@ import java.util.List; import java.util.Set; +import javax.ws.rs.core.MediaType; + import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; @@ -20,6 +22,7 @@ import org.codehaus.jackson.type.JavaType; import com.google.common.base.Joiner; +import com.google.common.base.Optional; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.palantir.code.ts.generator.model.InnerServiceModel; @@ -124,7 +127,8 @@ public void emitTypescriptClass() { writer.writeLine("endpointPath: \"" + getEndpointPathString(innerServiceModel, endpointModel) + "\","); writer.writeLine("endpointName: \"" + endpointModel.endpointName() + "\","); writer.writeLine("method: \"" + endpointModel.endpointMethodType() + "\","); - writer.writeLine("mediaType: \"" + endpointModel.endpointMediaType() + "\","); + writer.writeLine("requestMediaType: \"" + endpointModel.endpointRequestMediaType() + "\","); + writer.writeLine("responseMediaType: \"" + optionalToString(endpointModel.endpointResponseMediaType()) + "\","); List requiredHeaders = Lists.newArrayList(); List pathArguments = Lists.newArrayList(); List queryArguments = Lists.newArrayList(); @@ -145,7 +149,7 @@ public void emitTypescriptClass() { if (parameterModel.javaType() instanceof Class) { isEnum = ((Class) parameterModel.javaType()).isEnum(); } - if (endpointModel.endpointMediaType().equals("application/json") && (parameterModel.tsType().toString().equals("string") || isEnum)) { + if (endpointModel.equals(MediaType.APPLICATION_JSON) && (parameterModel.tsType().toString().equals("string") || isEnum)) { // strings (and enums, the wire format of an enum is a string) have to be wrapped in quotes in order to be valid json dataArgument = "`\"${" + parameterModel.getParameterName() + "}\"`"; } @@ -313,4 +317,12 @@ public String getMappedName(Class cls) { } return ret; } + + private static String optionalToString(Optional payload) { + if (payload.isPresent()) { + return payload.get().toString(); + } + return ""; + } + } diff --git a/typescript-service-generator-core/src/main/java/com/palantir/code/ts/generator/model/ServiceEndpointModel.java b/typescript-service-generator-core/src/main/java/com/palantir/code/ts/generator/model/ServiceEndpointModel.java index ed4e899..59e0f53 100644 --- a/typescript-service-generator-core/src/main/java/com/palantir/code/ts/generator/model/ServiceEndpointModel.java +++ b/typescript-service-generator-core/src/main/java/com/palantir/code/ts/generator/model/ServiceEndpointModel.java @@ -7,10 +7,13 @@ import java.lang.reflect.Type; import java.util.List; +import javax.ws.rs.core.MediaType; + import org.immutables.value.Value; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.google.common.base.Optional; import com.palantir.code.ts.generator.ImmutableTypescriptServiceGeneratorConfiguration; import cz.habarta.typescript.generator.TsType; @@ -26,11 +29,14 @@ public abstract class ServiceEndpointModel implements Comparable endpointResponseMediaType(); + @Override public int compareTo(ServiceEndpointModel o) { return this.endpointName().compareTo(o.endpointName()); diff --git a/typescript-service-generator-core/src/main/resources/httpApiBridge.ts b/typescript-service-generator-core/src/main/resources/httpApiBridge.ts index a2320c7..2a7b8b7 100644 --- a/typescript-service-generator-core/src/main/resources/httpApiBridge.ts +++ b/typescript-service-generator-core/src/main/resources/httpApiBridge.ts @@ -3,7 +3,8 @@ export interface %sHttpEndpointOptions { endpointPath: string; endpointName: string; method: string; - mediaType: string; + requestMediaType: string; + responseMediaType: string; requiredHeaders: string[]; pathArguments: any[]; queryArguments: any; diff --git a/typescript-service-generator-core/src/test/java/com/palantir/code/ts/generator/ServiceClassParserTest.java b/typescript-service-generator-core/src/test/java/com/palantir/code/ts/generator/ServiceClassParserTest.java index 8e94b57..e6e6d91 100644 --- a/typescript-service-generator-core/src/test/java/com/palantir/code/ts/generator/ServiceClassParserTest.java +++ b/typescript-service-generator-core/src/test/java/com/palantir/code/ts/generator/ServiceClassParserTest.java @@ -15,6 +15,7 @@ import java.util.stream.Collectors; import javax.annotation.CheckForNull; +import javax.ws.rs.core.MediaType; import org.junit.Before; import org.junit.Test; @@ -40,6 +41,7 @@ import com.palantir.code.ts.generator.utils.TestUtils.IgnoredParametersClass; import com.palantir.code.ts.generator.utils.TestUtils.ImmutablesObject; import com.palantir.code.ts.generator.utils.TestUtils.MyObject; +import com.palantir.code.ts.generator.utils.TestUtils.PlainTextService; import com.palantir.code.ts.generator.utils.TestUtils.SimpleService1; import com.palantir.code.ts.generator.utils.TestUtils.SimpleService2; import com.palantir.code.ts.generator.utils.TestUtils.TestComplexServiceClass; @@ -112,6 +114,7 @@ public void parseComplexClassTest() throws NoSuchMethodException, SecurityExcept .endpointName("allOptionsPost") .endpointPath("allOptionsPost/{a}") .endpointMethodType("POST") + .endpointRequestMediaType(MediaType.APPLICATION_JSON) .build()); } { @@ -253,4 +256,38 @@ public void multipleServiceClassParseTest() { assertEquals(expectedServiceModel, model); } + @Test + public void plainTextTest() { + ServiceModel model = serviceClassParser.parseServiceClass(PlainTextService.class, settings); + + ImmutableServiceEndpointParameterModel expectedParameterModel = ImmutableServiceEndpointParameterModel.builder() + .javaType(String.class) + .tsType(TsType.String) + .build(); + + ImmutableServiceEndpointModel expectedEndpointModel = ImmutableServiceEndpointModel.builder() + .javaReturnType(String.class) + .tsReturnType(TsType.String) + .addParameters(expectedParameterModel) + .endpointName("plainText") + .endpointPath("plainText") + .endpointMethodType("GET") + .endpointRequestMediaType(MediaType.TEXT_PLAIN) + .endpointResponseMediaType(MediaType.TEXT_PLAIN) + .build(); + InnerServiceModel innerServiceModel = ImmutableInnerServiceModel.builder() + .addEndpointModels(expectedEndpointModel) + .servicePath("plainTextService") + .name("PlainTextService") + .build(); + + ServiceModel expectedServiceModel = ImmutableServiceModel.builder() + .addInnerServiceModels(innerServiceModel) + .name("PlainTextService") + .addReferencedTypes(String.class) + .build(); + + assertEquals(expectedServiceModel, model); + } + } diff --git a/typescript-service-generator-core/src/test/java/com/palantir/code/ts/generator/ServiceEmitterTest.java b/typescript-service-generator-core/src/test/java/com/palantir/code/ts/generator/ServiceEmitterTest.java index 5755213..b9682f7 100644 --- a/typescript-service-generator-core/src/test/java/com/palantir/code/ts/generator/ServiceEmitterTest.java +++ b/typescript-service-generator-core/src/test/java/com/palantir/code/ts/generator/ServiceEmitterTest.java @@ -107,7 +107,8 @@ public void testComplexServiceClassEmitClass() { " endpointPath: \"testComplexService/allOptionsPost/{a}\",\n" + " endpointName: \"allOptionsPost\",\n" + " method: \"POST\",\n" + -" mediaType: \"application/json\",\n" + +" requestMediaType: \"application/json\",\n" + +" responseMediaType: \"\",\n" + " requiredHeaders: [],\n" + " pathArguments: [a],\n" + " queryArguments: {\n" + @@ -124,7 +125,8 @@ public void testComplexServiceClassEmitClass() { " endpointPath: \"testComplexService/queryGetter\",\n" + " endpointName: \"queryGetter\",\n" + " method: \"GET\",\n" + -" mediaType: \"application/json\",\n" + +" requestMediaType: \"application/json\",\n" + +" responseMediaType: \"\",\n" + " requiredHeaders: [],\n" + " pathArguments: [],\n" + " queryArguments: {\n" + @@ -141,7 +143,8 @@ public void testComplexServiceClassEmitClass() { " endpointPath: \"testComplexService/simplePut\",\n" + " endpointName: \"simplePut\",\n" + " method: \"PUT\",\n" + -" mediaType: \"application/json\",\n" + +" requestMediaType: \"application/json\",\n" + +" responseMediaType: \"\",\n" + " requiredHeaders: [],\n" + " pathArguments: [],\n" + " queryArguments: {\n" + @@ -205,7 +208,8 @@ public void testConcreteObjectService() { " endpointPath: \"concreteObject\",\n" + " endpointName: \"noPathGetter\",\n" + " method: \"GET\",\n" + -" mediaType: \"application/json\",\n" + +" requestMediaType: \"application/json\",\n" + +" responseMediaType: \"\",\n" + " requiredHeaders: [],\n" + " pathArguments: [],\n" + " queryArguments: {\n" + diff --git a/typescript-service-generator-core/src/test/java/com/palantir/code/ts/generator/utils/TestUtils.java b/typescript-service-generator-core/src/test/java/com/palantir/code/ts/generator/utils/TestUtils.java index f1be195..0b79898 100644 --- a/typescript-service-generator-core/src/test/java/com/palantir/code/ts/generator/utils/TestUtils.java +++ b/typescript-service-generator-core/src/test/java/com/palantir/code/ts/generator/utils/TestUtils.java @@ -5,12 +5,15 @@ package com.palantir.code.ts.generator.utils; import javax.annotation.CheckForNull; +import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; import org.immutables.value.Value; @@ -41,6 +44,7 @@ public interface TestComplexServiceClass { @POST @Path("/allOptionsPost/{a}") + @Consumes(MediaType.APPLICATION_JSON) GenericObject allOptionsPost(@PathParam("a") String a, @QueryParam("b") Integer x, DataObject dataObject); } @@ -97,6 +101,16 @@ public String noPathGetter() { }; } + @Path("/plainTextService") + public interface PlainTextService { + + @GET + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + @Path("/plainText") + public String plainText(String dataBody); + } + public enum MyEnum { VALUE1, VALUE2 } diff --git a/typescript-service-generator-core/src/test/resources/eteTestData/complexServiceTestOutput/httpApiBridge.ts b/typescript-service-generator-core/src/test/resources/eteTestData/complexServiceTestOutput/httpApiBridge.ts index 0f36274..cb45e45 100644 --- a/typescript-service-generator-core/src/test/resources/eteTestData/complexServiceTestOutput/httpApiBridge.ts +++ b/typescript-service-generator-core/src/test/resources/eteTestData/complexServiceTestOutput/httpApiBridge.ts @@ -7,7 +7,8 @@ module ModuleName { endpointPath: string; endpointName: string; method: string; - mediaType: string; + requestMediaType: string; + responseMediaType: string; requiredHeaders: string[]; pathArguments: any[]; queryArguments: any; diff --git a/typescript-service-generator-core/src/test/resources/eteTestData/complexServiceTestOutput/testComplexServiceClass.ts b/typescript-service-generator-core/src/test/resources/eteTestData/complexServiceTestOutput/testComplexServiceClass.ts index fb2d4e0..deec0cf 100644 --- a/typescript-service-generator-core/src/test/resources/eteTestData/complexServiceTestOutput/testComplexServiceClass.ts +++ b/typescript-service-generator-core/src/test/resources/eteTestData/complexServiceTestOutput/testComplexServiceClass.ts @@ -37,7 +37,8 @@ module ModuleName.TestComplexServiceClass { endpointPath: "testComplexService/allOptionsPost/{a}", endpointName: "allOptionsPost", method: "POST", - mediaType: "application/json", + requestMediaType: "application/json", + responseMediaType: "", requiredHeaders: [], pathArguments: [a], queryArguments: { @@ -54,7 +55,8 @@ module ModuleName.TestComplexServiceClass { endpointPath: "testComplexService/queryGetter", endpointName: "queryGetter", method: "GET", - mediaType: "application/json", + requestMediaType: "application/json", + responseMediaType: "", requiredHeaders: [], pathArguments: [], queryArguments: { @@ -71,7 +73,8 @@ module ModuleName.TestComplexServiceClass { endpointPath: "testComplexService/simplePut", endpointName: "simplePut", method: "PUT", - mediaType: "application/json", + requestMediaType: "application/json", + responseMediaType: "", requiredHeaders: [], pathArguments: [], queryArguments: { diff --git a/typescript-service-generator-core/src/test/resources/eteTestData/simpleServiceTestOutput/httpApiBridge.ts b/typescript-service-generator-core/src/test/resources/eteTestData/simpleServiceTestOutput/httpApiBridge.ts index 94857de..d355e8f 100644 --- a/typescript-service-generator-core/src/test/resources/eteTestData/simpleServiceTestOutput/httpApiBridge.ts +++ b/typescript-service-generator-core/src/test/resources/eteTestData/simpleServiceTestOutput/httpApiBridge.ts @@ -6,7 +6,8 @@ export interface HttpEndpointOptions { endpointPath: string; endpointName: string; method: string; - mediaType: string; + requestMediaType: string; + responseMediaType: string; requiredHeaders: string[]; pathArguments: any[]; queryArguments: any; diff --git a/typescript-service-generator-core/src/test/resources/eteTestData/simpleServiceTestOutput/simpleService1.ts b/typescript-service-generator-core/src/test/resources/eteTestData/simpleServiceTestOutput/simpleService1.ts index 6a57ca2..f6a2d14 100644 --- a/typescript-service-generator-core/src/test/resources/eteTestData/simpleServiceTestOutput/simpleService1.ts +++ b/typescript-service-generator-core/src/test/resources/eteTestData/simpleServiceTestOutput/simpleService1.ts @@ -19,7 +19,8 @@ export class SimpleService1Impl implements SimpleService1 { endpointPath: "simple1/method1", endpointName: "method1", method: "GET", - mediaType: "application/json", + requestMediaType: "application/json", + responseMediaType: "", requiredHeaders: [], pathArguments: [], queryArguments: {