Skip to content

Commit

Permalink
feat: Add backstage
Browse files Browse the repository at this point in the history
  • Loading branch information
ArneLimburg committed Oct 10, 2023
1 parent 2a0855a commit 1b96ba9
Show file tree
Hide file tree
Showing 116 changed files with 25,501 additions and 61 deletions.
29 changes: 29 additions & 0 deletions address-validation-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,35 @@
<artifactId>microprofile-config-api</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile.openapi</groupId>
<artifactId>microprofile-openapi-api</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo</groupId>
<artifactId>geronimo-openapi-impl</artifactId>
<version>1.0.12</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.10.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>swagger-ui</artifactId>
<version>5.4.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
Expand Down Expand Up @@ -55,11 +54,6 @@ public class AddressResource {
@Inject
private AddressRepository addressesRepository;

@GET
public Response healthCheck() {
return Response.ok().build();
}

@POST
@Path("/")
@Consumes(MediaType.APPLICATION_JSON)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*/
package de.openknowledge.sample.address.domain;

import org.eclipse.microprofile.openapi.annotations.media.Schema;

@Schema(name = "Address")
public class Address {
private Street street;
private City city;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@

import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.Validate.notNull;
import static org.eclipse.microprofile.openapi.annotations.enums.SchemaType.STRING;

import java.util.List;
import java.util.stream.Stream;

import javax.json.bind.adapter.JsonbAdapter;
import javax.json.bind.annotation.JsonbTypeAdapter;

import org.eclipse.microprofile.openapi.annotations.media.Schema;

import de.openknowledge.sample.address.domain.City.Adapter;

@Schema(name = "City")
@JsonbTypeAdapter(Adapter.class)
public class City {

Expand All @@ -48,10 +52,12 @@ protected City() {
// for framework
}

@Schema(type = STRING, pattern = "^\\d{5}$", example = "26122")
public ZipCode getZipCode() {
return new ZipCode(name.substring(0, 5));
}

@Schema(hidden = true)
public List<CityName> getCityNames() {
String names = name.substring(5);
if (names.endsWith("u.a.")) {
Expand All @@ -60,6 +66,7 @@ public List<CityName> getCityNames() {
return Stream.of(names.split(",")).map(CityName::new).collect(toList());
}

@Schema(type = STRING, example = "Oldenburg")
public CityName getCityName() {
return getCityNames().iterator().next();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@
package de.openknowledge.sample.address.domain;

import static org.apache.commons.lang3.Validate.notNull;
import static org.eclipse.microprofile.openapi.annotations.enums.SchemaType.STRING;

import javax.json.bind.annotation.JsonbCreator;
import javax.json.bind.annotation.JsonbProperty;

import org.eclipse.microprofile.openapi.annotations.media.Schema;

@Schema(name = "Street")
public class Street {

private StreetName name;
Expand All @@ -31,10 +35,12 @@ public Street(@JsonbProperty("name") StreetName name, @JsonbProperty("number") H
this.number = notNull(houseNumber, "house number may not be null");
}

@Schema(type = STRING, example = "Poststr.")
public StreetName getName() {
return name;
}

@Schema(type = STRING, example = "1")
public HouseNumber getNumber() {
return number;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.openknowledge.sample.address.infrastructure;
package de.openknowledge.sample.infrastructure.jaxrs;

import java.io.IOException;

import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;

/**
* Filter to allow cross origin calls.
*/
@Provider
@ApplicationScoped
public class CORSFilter implements ContainerResponseFilter {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.openknowledge.sample.address.infrastructure;
package de.openknowledge.sample.infrastructure.jaxrs;

import javax.enterprise.context.ApplicationScoped;
import javax.validation.ValidationException;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2019 - 2023 open knowledge GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.openknowledge.sample.infrastructure.openapi;

import java.util.Map.Entry;

import org.eclipse.microprofile.openapi.OASFilter;
import org.eclipse.microprofile.openapi.models.Components;
import org.eclipse.microprofile.openapi.models.OpenAPI;
import org.eclipse.microprofile.openapi.models.PathItem;

public class OpenApiFilter implements OASFilter {

public void filterOpenAPI(OpenAPI openApi) {
for (Entry<String, PathItem> item: openApi.getPaths().getPathItems().entrySet()) {
if (item.getKey().startsWith("/metrics") || item.getKey().startsWith("/health") || item.getKey().contains("webjars")) {
openApi.getPaths().removePathItem(item.getKey());
}
}
Components components = openApi.getComponents();
components.removeSchema("void");
components.removeSchema("java_lang_Object");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2023 open knowledge GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.openknowledge.sample.swaggerui;

import static java.util.logging.Level.WARNING;
import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.util.logging.Logger;

import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;

/**
* RESTFul endpoint swaggerui
*/
@ApplicationScoped
@Path("{path: webjars/.*}")
public class SwaggerUiResource {

private final static Logger LOG = Logger.getLogger(SwaggerUiResource.class.getSimpleName());

@GET
public Response getWebJarsResource(@PathParam("path") String path) {
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(String.format("META-INF/resources/%s", path));
BufferedReader buffer = new BufferedReader(new InputStreamReader(inputStream));
StringWriter content = new StringWriter()) {
buffer.lines().forEach(content::write);

String mediaType = path.endsWith(".js") ? "application/javascript" : "text/" + path.substring(path.lastIndexOf('.') + 1);
return Response.ok(content.toString()).type(mediaType).build();
} catch (NullPointerException e) {
LOG.log(WARNING, "Could not find resource [{0}]", path);
return Response.status(NOT_FOUND).build();
} catch (IOException e) {
LOG.severe(e.getMessage());
return Response.status(INTERNAL_SERVER_ERROR).build();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mp.openapi.filter=de.openknowledge.sample.infrastructure.openapi.OpenApiFilter
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./5.4.2/swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="./5.4.2/index.css" />
<link rel="icon" type="image/png" href="./5.4.2/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./5.4.2/favicon-16x16.png" sizes="16x16" />
</head>

<body>
<div id="swagger-ui"></div>
<script src="./5.4.2/swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./5.4.2/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = function() {
window.ui = SwaggerUIBundle({
urls: [
{
name: "Address Validation Service",
url: "../../openapi"
}
],
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});
};
</script>
</body>
</html>
80 changes: 80 additions & 0 deletions backstage/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Stage 1 - Create yarn install skeleton layer
FROM node:18-bullseye-slim AS packages

WORKDIR /app
COPY package.json yarn.lock ./

COPY packages packages

# Comment this out if you don't have any internal plugins
#COPY plugins plugins

RUN find packages \! -name "package.json" -mindepth 2 -maxdepth 2 -exec rm -rf {} \+

# Stage 2 - Install dependencies and build packages
FROM node:18-bullseye-slim AS build

# install sqlite3 dependencies
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && \
apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \
yarn config set python /usr/bin/python3

USER node
WORKDIR /app

COPY --from=packages --chown=node:node /app .

# Stop cypress from downloading it's massive binary.
ENV CYPRESS_INSTALL_BINARY=0
RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \
yarn install --frozen-lockfile --network-timeout 600000

COPY --chown=node:node . .

RUN yarn tsc
RUN yarn --cwd packages/backend build
# If you have not yet migrated to package roles, use the following command instead:
# RUN yarn --cwd packages/backend backstage-cli backend:bundle --build-dependencies

RUN mkdir packages/backend/dist/skeleton packages/backend/dist/bundle \
&& tar xzf packages/backend/dist/skeleton.tar.gz -C packages/backend/dist/skeleton \
&& tar xzf packages/backend/dist/bundle.tar.gz -C packages/backend/dist/bundle

# Stage 3 - Build the actual backend image and install production dependencies
FROM node:18-bullseye-slim

# Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image,
# in which case you should also move better-sqlite3 to "devDependencies" in package.json.
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && \
apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential curl && \
yarn config set python /usr/bin/python3

# From here on we use the least-privileged `node` user to run the backend.
USER node

# This should create the app dir as `node`.
# If it is instead created as `root` then the `tar` command below will fail: `can't create directory 'packages/': Permission denied`.
# If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) so the app dir is correctly created as `node`.
WORKDIR /app

# Copy the install dependencies from the build stage and context
COPY --from=build --chown=node:node /app/yarn.lock /app/package.json /app/packages/backend/dist/skeleton/ ./

RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \
yarn install --frozen-lockfile --production --network-timeout 600000

# Copy the built packages from the build stage
COPY --from=build --chown=node:node /app/packages/backend/dist/bundle/ ./

# Copy any other files that we need at runtime
COPY --chown=node:node app-config.yaml ./
COPY --chown=node:node examples /examples

# This switches many Node.js dependencies to production mode.
ENV NODE_ENV production

CMD ["node", "packages/backend", "--config", "app-config.yaml"]
Loading

0 comments on commit 1b96ba9

Please sign in to comment.