How to access vendor extensions in api.mustache regarding imports when endpoints are regrouped by tags - tags

Problem
The issue concerns swagger codegen and using multiple files to define specs.
I have two REST APIs with two different files specs1.yml and specs2.yml.
These specs have some models/schemas/definitions (I use swagger 2.0) in common.
I'd like to factorize these definitions in a core.yml file.
I can then reference these in specs1 and specs2.
The issue is that swagger codegen generates these models as part of specs1 and specs2. What I'd like is processing the core.yml file, generating classes in a core package, and then having the specs1/2 generated classes referencing the classes in the core package when it's a common one.
Technical Stack
Maven / Java / JAXRS-CXF REST API
Maven 3.6.0
Java 1.8.0_201
swagger-jaxrs 1.5.16
CXF 3.1.14
swagger-codegen-maven-plugin 2.4.7
Code Example
Swagger Specs YML
I have a tag named e.g. "Super Tag" in my swagger specs definition.
Multiple endpoints are regrouped under that tag. For the sake of a minimal PoC of my issue, let's go with one endpoint:
specs1.yml
swagger: "2.0"
tags:
- name: "Super Tag"
x-core-imports: [ErrorResponse] # Trying this at tag level
x-imports: [ABody] # Trying this at tag level
paths:
/someEndpointPath:
post:
x-core-imports: [ErrorResponse] # --> import bla.core.api.models.ErrorResponse
x-imports: [ABody] # --> import bla.project.api.models.ABody
tags:
- "Super Tag"
operationId: postToSomeEndpoint
consumes:
- application/json
produces:
- application/json
parameters:
- name: body
in: body
required: true
schema:
$ref: '#/definitions/ABody' # This model is defined in this file
responses:
204:
description: "Successful response"
400:
description: "Bad request error"
schema:
$ref: '../CORE.yml#/definitions/_ErrorResponse'
# I'm importing this model definition from another file
definitions:
ABody:
type: object
field:
type: string
Swagger Codegen Debugging
I tried seeing where the vendor extensions would be added with regards to imports: [{ "import": ... }] (which is what's read from the api.mustache template, see below)
> java -DdebugSupportingFiles -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar generate -i specs.yml -l java > result.json
I can see
result.json
"apiInfo" : {
"apis" : { [
"parent" : [ ],
"generatorClass" : "io.swagger.codegen.languages.JavaClientCodegen",
"supportJava6" : false,
"sortParamsByRequiredFlag" : true,
"groupId" : "io.swagger",
"invokerPackage" : "io.swagger.client",
"classVarName" : "superTag",
"developerEmail" : "apiteam#swagger.io",
"generateModelDocs" : true,
"hasImport" : true,
"generateModelTests" : true,
"generateApiTests" : true,
"classFilename" : "SuperTagApi",
"usePlayWS" : false,
"generateModels" : true,
"serializableModel" : false,
"playVersion" : "play25",
"inputSpec" : "specs.yml",
"artifactUrl" : "https://github.com/swagger-api/swagger-codegen",
"developerOrganization" : "Swagger",
"baseName" : "SuperTag",
"package" : "io.swagger.client.api",
"imports" : [ {
"import" : "io.swagger.client.model.ABody"
}, {
"import" : "io.swagger.client.model.ErrorResponse"
} ]
...
] }
}
Swagger Templates
We can see in the api.mustache template
package {{package}};
{{#imports}}import {{import}};
{{/imports}}
I'm using the maven swagger codegen plugin with the following options:
<modelPackage>com.mysite.myproject.api.models</modelPackage>
<apiPackage>com.mysite.myproject.api</apiPackage>
So in my generated java class I will get:
SuperTagApi.class
package com.mysite.myproject.api;
import com.mysite.myproject.api.models.ErrorResponse;
import com.mysite.myproject.api.models.ABody;
What I'd like to do is have a means to tell swaggercodegen that I want one class imported as it is now, but the second imported from another package.
To do that, my idea was using vendor extensions (as you can see above) and manually list the classes that I want imported from a given package (that will actually be generated from the CORE.yml file) and the ones that are defined in my specs.yml where I want the original generated package name.
I tried adding x-core-imports vendor-extension to multiple different places trying to get access to them. None put them at the same level as the imports: [{ "import": ... }] section of the result.json... This is because different endpoints/methods are regrouped under the same file when their tag is identical.
I modified my api.mustache like so:
{{^vendorExtensions.x-imports}}
{{#imports}}import {{import}};
{{/imports}}
{{/vendorExtensions.x-imports}}
{{#vendorExtensions.x-imports}}
{{#vendorExtensions.x-core-imports}}
import com.mysite.core.api.models.{{.}};
{{/vendorExtensions.x-core-imports}}
import com.mysite.myproject.api.models.{{.}};
{{/vendorExtensions.x-imports}}
Do you know at which level in the yml file I have to put my vendor extensions to be able to access them from api.mustache? (Without modifying swagger codegen, just modifying templates and yml specs files)

Related

Nuxt 3 "component library" module does not expose mixins of exported components in NX monorepo

I'm facing a problem with my Nuxt 3 component library.
It contains several Vue components which are then added to the exported components
export const useComponents = (nuxt: Nuxt) => {
const __dirname = dirname(fileURLToPath(import.meta.url));
let componentsDirectory = join(__dirname, "../", '/components');
nuxt.hooks.hook("components:dirs", (dirs) => {
dirs.push({
path: join(componentsDirectory, "../", 'atoms'),
prefix: 'base',
});
dirs.push({
path: join(componentsDirectory, "../", 'layout'),
prefix: 'base',
});
dirs.push({
path: join(componentsDirectory, "../", 'molecules'),
prefix: 'base',
});
})
}
However, some of those components are using mixins, which are located next to the components and relatively imported.
When using that component library in my application, it does not find the mixins and I'm getting this exception:
when using import loginButtonsMixing from "~/src/molecules/loginButtonsMixing.js";
[vite:load-fallback] Could not load
/home/user/workspace/my-project/apps/my-app/molecules/loginButtonsMixing.js
(imported by
../../../libs/general/base/src/molecules/LoginButtons.vue): ENOENT: no
such file or directory, open
'/home/user/workspace/my-project/apps/my-app/molecules/loginButtonsMixing.js'
It looks inside the app directory, instead of the library directory.
And when I'm using import loginButtonsMixing from "./loginButtonsMixing.js";
Could not resolve './loginButtonsMixing.js' from
../../../libs/base/src/molecules/LoginButtons.vue at error
(/home/user/workspace/my-project/node_modules/rollup/dist/es/shared/rollup.js:1858:30)
at ModuleLoader.handleResolveId
(/home/user/workspace/my-project/node_modules/rollup/dist/es/shared/rollup.js:22156:24)
at
/home/user/workspace/my-project/node_modules/rollup/dist/es/shared/rollup.js:22119:26
The path looks more or less correct, but rollup seems to fail.
How do I tell the Nuxt module to expose them as well?

url-loader without webpack?

I have a component library that will be shipping with a few small assets (images). Those assets are imported into various components in the library.
The build script uses babel (without webpack) to transpile the js(x) to a build directory, and is currently dumping the images into build/assets/images.
This works when testing the build, but when using the component in another project (using webpack) the component tries to refer the node_modules folder:
Example component:
import myImage from './assets/images/myImage.png';
const MyComponent = () => (
<img src={myImage} />
);
export MyComponent;
Usage:
import MyComponent from 'myLibrary/MyComponent';
export default () => (
<MyComponent />
);
The error message:
myImage.png:1 GET http://localhost:9001/node_modules/myLibrary/assets/images/myImage.png 404 (Not Found)
As I understand the 'best' way to include assets is to use the url-loader so they're converted to data uri's. However, trying to use the url-loader without Webpack isn't working:
babel.config.js
...
plugins: [
[
"url-loader",
{
"extensions": ["png", "jpg", "jpeg", "gif", "svg", "pdf"],
"limit": 0
}
]
]
...
Error: Cannot find module 'babel-plugin-url-loader'
I found this and it works for PNG and SVG files - worked perfectly for what I needed!
https://www.npmjs.com/package/babel-plugin-inline-import-data-uri

Build micronaut native image with hikari datasource

Faced with a problem running micronaut application that was packed in native-image.
I created simple demo application with micronaut-data-hibernate-jpa and based on documentation I need to add some db connection pool. I chose hikari and added such dependency micronaut-jdbc-hikari.
I use maven as build tool and add plugin to build native-image native-image-maven-plugin
native-image.properties
Args = -H:IncludeResources=logback.xml|application.yml|bootstrap.yml \
-H:Name=demo \
-H:Class=com.example.Application \
-H:+TraceClassInitialization \
--initialize-at-run-time=org.apache.commons.logging.LogAdapter$Log4jLog,org.hibernate.secure.internal.StandardJaccServiceImpl,org.postgresql.sspi.SSPIClient,org.hibernate.dialect.OracleTypesHelper \
--initialize-at-build-time=org.postgresql.Driver,org.postgresql.util.SharedTimer,org.hibernate.engine.spi.EffectiveEntityGraph,org.hibernate.engine.spi.LoadQueryInfluencers
When I run application with the jvm then everything works. But when I try to run same application that was packed as native-image then I get such error
Caused by: java.lang.IllegalArgumentException: Class com.zaxxer.hikari.util.ConcurrentBag$IConcurrentBagEntry[] is instantiated reflectively but was never registered. Register the class by using org.graalvm.nativeimage.hosted.RuntimeReflection
at com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets.arrayHubErrorStub(SubstrateAllocationSnippets.java:280)
at java.lang.ThreadLocal$SuppliedThreadLocal.initialValue(ThreadLocal.java:305)
at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:195)
at java.lang.ThreadLocal.get(ThreadLocal.java:172)
at com.zaxxer.hikari.util.ConcurrentBag.borrow(ConcurrentBag.java:129)
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:179)
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:161)
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:100)
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
at org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:38)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:104)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:134)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getConnectionForTransactionManagement(LogicalConnectionManagedImpl.java:250)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:258)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:246)
at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:83)
at org.hibernate.internal.AbstractSharedSessionContract.beginTransaction(AbstractSharedSessionContract.java:471)
at io.micronaut.transaction.hibernate5.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:352)
... 99 common frames omitted
UPDATE/SOLUTION
Based on #Airy answer I have added reflection config in native-image.properties. In my case it is looks like so
[
{
"name" : "com.zaxxer.hikari.util.ConcurrentBag",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"allDeclaredClasses" : true,
"allPublicClasses" : true
},
{
"name" : "com.zaxxer.hikari.pool.PoolEntry",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"allDeclaredClasses" : true,
"allPublicClasses" : true
}
]
And another solution is to change scope of hikari dependency to compile and add missed fields/classes into hints annotation like so
#TypeHint(value = {
PostgreSQL95Dialect.class,
SessionFactoryImpl.class,
org.postgresql.PGProperty.class,
UUIDGenerator.class,
com.zaxxer.hikari.util.ConcurrentBag.class, // In my case I have just added this line
}, accessType = {TypeHint.AccessType.ALL_PUBLIC})
whole example you can find here
You should declare reflection configuration in your native-image.properties with -H:ReflectionConfigurationFiles=/path/to/reflectconfig
Here is the documentation for doing so

OpenAPI get Documentation only for one Path?

I'm using OpenAPI to Document a Microprofile application. As the Endpoint contains a large set of methods, I'd like to know if it's possible to filter through the /openapi REST, so that it returns just a specific Path, for example "/users".
Thanks
You can have multiple paths selected. In openapi file the whole path section is called "paths" (so even the name is plural). If you're not sure how to use it, walk through openapi's in the "search" section of Swagger portal (you need to be logged in for this).
Example:
paths:
/{users}:
options:
security:
summary: "Temp summary"
description: "Temp description"
tags:
- "TAG"
parameters:
..
/test/{table}:
options:
security:
summary: "Temp summary"
description: "Temp description"
tags:
- "TAG"
parameters:
..
/test2/user/{id}:
options:
security:
summary: "Temp summary"
description: "Temp description"
tags:
- "TAG"
parameters:
as per our use case we found this to be working.
Annotate your endpoint with #Operation and add a hidden = true parameter to the annotation.
Here in Kotlin:
#GET #Path("/{id}")
#Operation(
summary = "your summary",
hidden = true
)
fun getDataset(#RestPath id: String): Response {
....
}

Karma preprocessor not running

My karma.conf.js includes:
plugins: [
'karma-jasmine',
'karma-phantomjs-launcher',
'karma-ng-html2js-preprocessor'
],
preprocessors: {
'../../mypath/*.html': ['ng-html2js']
},
ngHtml2JsPreprocessor: {
moduleName: 'templates'
},
(I've tried without specifying any plugins, too.)
My devDependencies include:
"karma-ng-html2js-preprocessor": "^0.2.0"`
My tests include:
beforeEach(module('templates'));
These give the error:
Module 'templates' is not available!
Running karma with --log-level debug, I do not see any [preprocessor.html2js] entries. (I do get Loading plugin karma-ng-html2js-preprocessor.)
What am I doing wrong?
The issues were that the templates must be listed under files as well, and that the glob pattern in preprocessors must match. This is implied by the documentation.
files: [
'../../Scripts/angular-app/directives/*.html',
// .js files
],
preprocessors: {
'../../Scripts/angular-app/**/*.html': ['ng-html2js']
},
Note that **/*.html does not match parent directories of the basePath.
karma start --log-level debug will display DEBUG [preprocessor.html2js] entries when everything is correct.
I was also able to remove the plugins section.
To get the correct cache ID, I used:
ngHtml2JsPreprocessor: {
// Load this module in your tests of directives that have a templateUrl.
moduleName: 'templates',
cacheIdFromPath: function (filepath) {
return filepath.substring(filepath.indexOf('/Scripts/angular-app/'));
}
},
If a template references a custom filter, the filter must be loaded in files and the filter's module must be loaded in your directive tests.