diff --git a/core/src/main/java/com/linecorp/armeria/internal/annotation/AnnotatedHttpDocServicePlugin.java b/core/src/main/java/com/linecorp/armeria/internal/annotation/AnnotatedHttpDocServicePlugin.java index 85523a1e5bf1..413928a11d50 100644 --- a/core/src/main/java/com/linecorp/armeria/internal/annotation/AnnotatedHttpDocServicePlugin.java +++ b/core/src/main/java/com/linecorp/armeria/internal/annotation/AnnotatedHttpDocServicePlugin.java @@ -152,20 +152,19 @@ private static void addServiceDescription(Map, String> serviceDescripti private static void addMethodInfo(Map, Set> methodInfos, String hostnamePattern, AnnotatedHttpService service) { final List routes = service.routes(); - routes.forEach(route -> { - final EndpointInfo endpoint = endpointInfo(route, hostnamePattern); - final Method method = service.method(); - final String name = method.getName(); - final TypeSignature returnTypeSignature = toTypeSignature(method.getGenericReturnType()); - final List fieldInfos = fieldInfos(service.annotatedValueResolvers()); - final Class clazz = service.object().getClass(); - route.methods().forEach( - httpMethod -> { - final MethodInfo methodInfo = new MethodInfo( - name, returnTypeSignature, fieldInfos, ImmutableList.of(), // Ignore exceptions. - ImmutableList.of(endpoint), httpMethod, findDescription(method)); - methodInfos.computeIfAbsent(clazz, unused -> new HashSet<>()).add(methodInfo); - }); + final List endpointInfos = + routes.stream().map(route -> endpointInfo(route, hostnamePattern)) + .collect(Collectors.toList()); + final Method method = service.method(); + final String name = method.getName(); + final TypeSignature returnTypeSignature = toTypeSignature(method.getGenericReturnType()); + final List fieldInfos = fieldInfos(service.annotatedValueResolvers()); + final Class clazz = service.object().getClass(); + routes.stream().flatMap(route -> route.methods().stream()).forEach(httpMethod -> { + final MethodInfo methodInfo = new MethodInfo( + name, returnTypeSignature, fieldInfos, ImmutableList.of(), // Ignore exceptions. + endpointInfos, httpMethod, findDescription(method)); + methodInfos.computeIfAbsent(clazz, unused -> new HashSet<>()).add(methodInfo); }); } diff --git a/core/src/test/java/com/linecorp/armeria/internal/annotation/AnnotatedHttpDocServiceTest.java b/core/src/test/java/com/linecorp/armeria/internal/annotation/AnnotatedHttpDocServiceTest.java index 6c1ae636166d..6bd53da93295 100644 --- a/core/src/test/java/com/linecorp/armeria/internal/annotation/AnnotatedHttpDocServiceTest.java +++ b/core/src/test/java/com/linecorp/armeria/internal/annotation/AnnotatedHttpDocServiceTest.java @@ -373,6 +373,13 @@ public HttpResponse exclude1() { public HttpResponse exclude2() { return HttpResponse.of(200); } + + @Get + @Path("/multi") + @Path("prefix:/multi2") + public HttpResponse multi() { + return HttpResponse.of(200); + } } private enum MyEnum { diff --git a/docs-client/src/containers/MethodPage/Endpoints.tsx b/docs-client/src/containers/MethodPage/Endpoints.tsx index 2ce109348285..4c92615bc282 100644 --- a/docs-client/src/containers/MethodPage/Endpoints.tsx +++ b/docs-client/src/containers/MethodPage/Endpoints.tsx @@ -24,15 +24,31 @@ import TableHead from '@material-ui/core/TableHead'; import TableRow from '@material-ui/core/TableRow'; import Typography from '@material-ui/core/Typography'; import * as React from 'react'; -import { Endpoint, Method } from '../../lib/specification'; +import {Endpoint, Method, Service, Specification} from '../../lib/specification'; import Section from '../../components/Section'; +import DebugPage from "./DebugPage"; +import {RouteComponentProps} from "react-router"; +import {TRANSPORTS} from "../../lib/transports"; +import {Option} from "react-dropdown"; -interface Props { +interface OwnProps { method: Method; + specification: Specification; } +type Props = OwnProps & + RouteComponentProps<{ + serviceName: string; + methodName: string; + httpMethod: string; + }>; + const Endpoints: React.SFC = (props) => { + const service = props.specification.getServiceByName( + props.match.params.serviceName, + ); + return (
Endpoints @@ -69,6 +85,20 @@ const Endpoints: React.SFC = (props) => { ))} + ))} @@ -85,4 +115,48 @@ function endpointPathString(endpoint: Endpoint): string { return endpoint.pathMapping; } +function isExactPathMapping(method: Method): boolean { + const endpoints = method.endpoints; + const endpoint = endpoints[0]; + return endpoint.pathMapping.startsWith('exact:'); +} + +function useRequestBody(httpMethod: string) { + return httpMethod === 'POST' || httpMethod === 'PUT'; +} + +function getExampleHeaders( + specification: Specification, + service: Service, + method: Method, +): Option[] { + const exampleHeaders: Option[] = []; + addExampleHeadersIfExists(exampleHeaders, method.exampleHttpHeaders); + addExampleHeadersIfExists(exampleHeaders, service.exampleHttpHeaders); + addExampleHeadersIfExists( + exampleHeaders, + specification.getExampleHttpHeaders(), + ); + return exampleHeaders; +} + +function addExampleHeadersIfExists( + dst: Option[], + src: { [name: string]: string }[], +) { + if (src.length > 0) { + for (const headers of src) { + dst.push({ + value: JSON.stringify(headers, null, 2), + label: removeBrackets(JSON.stringify(headers).trim()), + }); + } + } +} + +function removeBrackets(headers: string): string { + const length = headers.length; + return headers.substring(1, length - 1).trim(); +} + export default Endpoints; diff --git a/docs-client/src/containers/MethodPage/index.tsx b/docs-client/src/containers/MethodPage/index.tsx index b1021390abf0..1f9394004296 100644 --- a/docs-client/src/containers/MethodPage/index.tsx +++ b/docs-client/src/containers/MethodPage/index.tsx @@ -23,21 +23,14 @@ import TableCell from '@material-ui/core/TableCell'; import TableRow from '@material-ui/core/TableRow'; import Typography from '@material-ui/core/Typography'; import React from 'react'; -import { Option } from 'react-dropdown'; -import { RouteComponentProps } from 'react-router-dom'; - -import { - Method, - Service, - simpleName, - Specification, -} from '../../lib/specification'; -import { TRANSPORTS } from '../../lib/transports'; -import { ANNOTATED_HTTP_MIME_TYPE } from '../../lib/transports/annotated-http'; +import {RouteComponentProps} from 'react-router-dom'; + +import {simpleName, Specification,} from '../../lib/specification'; +import {TRANSPORTS} from '../../lib/transports'; +import {ANNOTATED_HTTP_MIME_TYPE} from '../../lib/transports/annotated-http'; import Section from '../../components/Section'; import VariableList from '../../components/VariableList'; -import DebugPage from './DebugPage'; import Endpoints from './Endpoints'; import Exceptions from './Exceptions'; @@ -107,73 +100,15 @@ const MethodPage: React.SFC = (props) => { {!isAnnotatedHttpService && ( )} - - {debugTransport && ( - - )} + ); }; -function getExampleHeaders( - specification: Specification, - service: Service, - method: Method, -): Option[] { - const exampleHeaders: Option[] = []; - addExampleHeadersIfExists(exampleHeaders, method.exampleHttpHeaders); - addExampleHeadersIfExists(exampleHeaders, service.exampleHttpHeaders); - addExampleHeadersIfExists( - exampleHeaders, - specification.getExampleHttpHeaders(), - ); - return exampleHeaders; -} -function addExampleHeadersIfExists( - dst: Option[], - src: { [name: string]: string }[], -) { - if (src.length > 0) { - for (const headers of src) { - dst.push({ - value: JSON.stringify(headers, null, 2), - label: removeBrackets(JSON.stringify(headers).trim()), - }); - } - } -} -function removeBrackets(headers: string): string { - const length = headers.length; - return headers.substring(1, length - 1).trim(); -} -function isExactPathMapping(method: Method): boolean { - const endpoints = method.endpoints; - if (endpoints.length !== 1) { - throw new Error(` - Endpoints size should be 1 to determine prefix or regex. size: ${endpoints.length}`); - } - const endpoint = endpoints[0]; - return endpoint.pathMapping.startsWith('exact:'); -} -function useRequestBody(httpMethod: string) { - return httpMethod === 'POST' || httpMethod === 'PUT'; -} + export default MethodPage; diff --git a/docs-client/src/lib/transports/index.ts b/docs-client/src/lib/transports/index.ts index 0feceea93492..f0d65cde18b5 100644 --- a/docs-client/src/lib/transports/index.ts +++ b/docs-client/src/lib/transports/index.ts @@ -14,9 +14,9 @@ * under the License. */ -import { Method } from '../specification'; +import {Method} from '../specification'; -import AnnotatedHttpTransport from './annotated-http'; +import AnnotatedHttpTransport, {ANNOTATED_HTTP_MIME_TYPE} from './annotated-http'; import GrpcUnframedTransport from './grpc-unframed'; import ThriftTransport from './thrift'; import Transport from './transport'; @@ -46,6 +46,11 @@ export class Transports { } return undefined; } + + public isAnnotatedService(method: Method): boolean { + const debugTransport = this.getDebugTransport(method); + return debugTransport !== undefined && debugTransport.supportsMimeType(ANNOTATED_HTTP_MIME_TYPE); + } } export const TRANSPORTS = new Transports();