Disclaimer: This blog post is only applicable for the SAP Cloud SDK version of at most 2.19.2. We plan to continuously migrate these blog posts into our List of Tutorials. Feel free to check out our updated Tutorials on the SAP Cloud SDK.
openapi: 3.0.0
info:
title: Sample API
description: Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.
version: 0.1.9
servers:
- url: http://api.example.com/v1
description: Optional server description, e.g. Main (production) server
- url: http://staging-api.example.com
description: Optional server description, e.g. Internal staging server for testing
paths:
/users:
get:
summary: Returns a list of users.
description: Optional extended description in CommonMark or HTML.
responses:
'200': # status code
description: A JSON array of user names
content:
application/json:
schema:
type: array
items:
type: string
openapi: 3.0.0
info
section, which contains API information like title
, version
and description
(optional)servers
specifies the API servers with base URL
and optional description
paths
defines individual endpoints of in your API, and the HTTP methods (operations) supported by these endpoints. An operation definition includes parameters (if any), request body (if any), possible response status codes (such as 200 OK or 404 Not Found) and response contents.<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>RELEASE</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/api.yaml</inputSpec>
<generatorName>java</generatorName>
<configOptions>
<java8>true</java8>
<dateLibrary>jave8</dateLibrary>
<library>resttemplate</library>
<sourceFolder>src/gen/java/main</sourceFolder>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
version
to the latest version available in the Maven central repository. This will ensure consistency and reproducibility among multiple builds. Also change the path definition in inputSpec
to your preferred api file. We highly recommend placing the OpenAPI file into the resources directory of your application.library
. This is our minimal setup recommendation to ensure library support with SAP Cloud SDK. Of course, there are many other parameters which can be set, to customize the generated code. Please find the official documentationonline.generate-sources
. In return, the generated code will vanish during the phase clean
. Hence by running the full build routine, a fresh code generation is triggered automatically:mvn clean install
HttpClient
and propagate it to the framework which calls an OpenAPI.HttpClient
already contains proxy settings and authentication headers, automatically resolved from the platform abstraction:// create a new HttpClient for SCP destination called: MyDestination
final String DESTINATION_NAME = "MyDestination";
final HttpClient httpClient = HttpClientAccessor.getHttpClient(DESTINATION_NAME);
// ... manually run a HttpRequest with the instance
HttpClient
on hand like above, or by using one of the libraries, suggested by the OpenAPI code generator.HttpClient
prepared by Cloud SDK needs to be injected to the automatically generated ApiClient
framework. With the generated object you can query all API actions as described in the OpenAPI interface.HttpClient
, but also a modification of ApiClient
. Here the base URL of the called REST service must be set at runtime, to ensure proper multi-tenancy and compliance of the registered destination.ApiClient
is changed to feature the correct destination-dependent endpoint path. For authorization and destination-dependent server URL, the instance of RestTemplate
is created. The HttpClient
is injected to the latter object.public ApiClient createApiClient() throws URISyntaxException
{
// resolve destination
final Destination destination = DestinationAccessor.getDestination(DESTINATION_NAME);
// instantiate RestTemplate and ApiClient
final RestTemplate restTemplate = createRestTemplate();
final ApiClient apiClient = new ApiClient(restTemplate);
// set root of API Client base path
final URI uri = destination.getUri();
final URI path = new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), null, null);
apiClient.setBasePath(path.toString());
return apiClient;
}
public RestTemplate createRestTemplate()
{
// create new HttpClient for destination
final HttpClient httpClient = HttpClientAccessor.getHttpClient(DESTINATION_NAME);
// instantiate template with prepared HttpClient, featuring repeated response reading
final RestTemplate restTemplate = new RestTemplate();
final HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setHttpClient(httpClient);
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(httpRequestFactory));
return restTemplate;
}
HttpClient
is injected to the Feign Builder by using the client modifier function of Feign Builder. As opposed to the other libraries, Feign works with interfaces, hence there is no implementation required for ApiClient
.public Feign.Builder createFeignBuilder() {
final HttpClient httpClient = HttpClientAccessor.getHttpClient(DESTINATION_NAME);
return Feign.builder()
.encoder(new FormEncoder(new JacksonEncoder(getObjectMapper())))
.decoder(new JacksonDecoder(getObjectMapper()))
.logger(new Slf4jLogger())
.client(new ApacheHttpClient(httpClient));
}
public <T extends ApiClient.Api> T buildApi(Class<T> apiClass) {
// resolve destination
final Destination destination = DestinationAccessor.getDestination(DESTINATION_NAME);
// set root of API Client base path
final URI uri = destination.getUri();
final URI path = new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), null, null);
Feign.Builder feignBuilder = createFeignBuilder();
return feignBuilder.target(apiClass, path.toString());
}
ApiClient
is created, by applying service path and the wrapped HttpClient
to the constructor.public ApiClient createHttpClient() {
// set root of API Client base path
final Destination destination = DestinationAccessor.getDestination(DESTINATION);
final URI uri = destination.getUri();
final URI path = new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), null, null);
// set HttpClient
final HttpClient httpClient = HttpClientAccessor.getHttpClient(destination);
final ApacheHttpTransport apacheHttpTransport = new ApacheHttpTransport(httpClient);
final HttpRequestInitializer initializer = null; // optional credentials
final ObjectMapper objectMapper = null; // optional Jackson ObjectMapper
return new ApiClient(path.toString(), apacheHttpTransport, initializer, objectMapper);
}
HttpClient
of Apache as interface for web requests, some frameworks may not work with injecting the client:HttpClient
of SAP Cloud SDK.gETSomething
), you can most likely fix the interface file. You can either do this manually by hand or automate this step as part of the Maven build, e.g.: <plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>1.5.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
<file>${project.basedir}/src/main/resources/api.yaml</file>
<outputFile>${project.basedir}/target/api.yaml.fixed</outputFile>
<regex>true</regex>
<replacements>
<replacement>
<token>operationId: GET(\w)</token>
<value>operationId: get$1</value>
</replacement>
<replacement>
<token>operationId: POST(\w)</token>
<value>operationId: post$1</value>
</replacement>
<replacement>
<token>operationId: PUT(\w)</token>
<value>operationId: put$1</value>
</replacement>
<replacement>
<token>operationId: DELETE(\w)</token>
<value>operationId: delete$1</value>
</replacement>
<replacement>
<token>operationId: OPTIONS(\w)</token>
<value>operationId: options$1</value>
</replacement>
<replacement>
<token>operationId: TRACE(\w)</token>
<value>operationId: trace$1</value>
</replacement>
<replacement>
<token>operationId: HEAD(\w)</token>
<value>operationId: head$1</value>
</replacement>
<replacement>
<token>operationId: CONNECT(\w)</token>
<value>operationId: connect$1</value>
</replacement>
</replacements>
</configuration>
</plugin>
api.yaml
. Instead a new fixed copy is created as ./target/api.yaml.fixed
. You will need to change your code generator plugin accordingly, such that it points to the fixed file.You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
17 | |
14 | |
12 | |
10 | |
9 | |
8 | |
7 | |
7 | |
6 | |
6 |