How to prevent models being generated with full namespace? - openapi

When I run openapi-generator-cli the Models and containing files are being output with their names containing the full namespace of the API classes. This is very awkward to read. I'd like the output to contain only the Model name, without the namespace.
E.g for class
namespace My.NameSpace.Common.V1.Models.Dto
{
public partial class PortfolioAsset
{
// properties
The output looks like
my-namespace-common-v1-models-dto-portfolio-asset.ts
With the content of the file as
export interface MyNamespaceCommonV1ModelsDtoPortfolioAsset {
// parameters
}
I just want the file to be called portfolio-asset.ts and the content to be
export interface PortfolioAsset {
// parameters
}
How can I do this?

The fix was simply to remove the CustomSchemaIds line, which specified that I should use the full name of each type being generated.
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = AppSettingsProvider.AppSettings.ApplicationName, Version = "v1" });
// c.CustomSchemaIds(x => x.FullName); <-- delete ftw
});

Related

Best practices in protractor for big pageObject files

In my previous protractor JS project (This new one I will do it with TS) I created one class for all my elements and another one for my functions, something like this:
specs
|_reportPage
|_lib
|_pageElements.js
|_pageFunctions.js
Then I was importing the files as necessary, in this way was easy to find the info since the element list was long.
So far all examples online for protractor TS projects are short pageObject files with a couple of elements and methods, but I would like to know how to correctly proceed when the page requires a lot of elements and functions/methods.
For example, lets say we have 5 specs under the same folder that test the same page and this page is full of fields and tables.
What would be the best practice here? create 1 pageobject for each spec, create one long class with all the elements and functions...?
Thanks for your time!
To Extend my answer you can add additional layer as a service which can execute several actions from the flow in different pages.
Code example:
export class E2EService {
mainPage: MainPage = new MainPage();
innerPage: InnerPage = new InnerPage();
doSomethingE2E() {
this.mainPage.headerPage.weDoSomething();
this.mainPage.contentPage.weDoSomething()
this.innerPage.somethingComplicated();
}
}
export class MainPage {
public readonly headerPage: HeaderPage;
public readonly contentPage: ContentPage;
}
export class InnerPage {
headerPage: InnerHeaderPage;
contentPage: InnerContentPage;
public somethingComplicated() {
this.headerPage.weDoSomething();
this.contentPage.weDoSomething();
}
}
export class ContentPage {
private readonly elements = {
// elements
};
public weDoSomething() {
// code
}
public getElements() {
return this.elements;
}
}
export class HeaderPage {
private readonly elements = {
btn1: element(by.id('')),
div: element(by.id('')),
h2: element(by.id(''))
};
public weDoSomething() {
// code
}
public getElements() {
return this.elements;
}
}
Based on Infern0's answer, I did dependency injection to the classes:
class HeaderElements {
foo = element(by.id("foo"));
//List goes on...
}
class HomePageElements {
foo = element(by.id("foo"));
//List goes on...
}
export class MainCommonElementsPage {
headerElements: HeaderElements;
homePageElements: HomePageElements;
constructor() {
this.headerElements = new HeaderElements();
this.homePageElements = new HomePageElements();
}
}
Best practices, even for large Page Objects is this:
Each page should only have 1 page object class. All of the tools needed to access that page should be located here. Think of your page object as an API.
Don't break the PO into different parts, especially for large pages. You'll eventually need to modify the PO to adjust for content changes. Would you rather change 1 file or 12? This also ensures that each of your e2e tests will remain functional after you update the PO.
I have one PO that handles a page with a lengthy form. The form has 12 controls and three buttons (cancel, reset, and submit). I have about 30 functions that deal with the form. I don't like having more than 1-2 methods in my test, so if it gets more complicated, I add to the PO.

RepositoryItem from List&Label .lst file

Currently we are using a WPF application for creation/editing of List&Label Templates, but we are considering to move to the WebDesigner. Because we use project includes we need to use the repository mode.
I've been trying to import our existing templates, but I run into some issues regarding the RepositoryItemDescriptor. To create a RepositoryItem object you have to give a Descriptor in the constructor, but I cannot find any info regarding how you get it from the generated .lst file.
The data that we have at our disposal are:
TemplateType: List or Form
TemplateData: content of the .lst file (byte[])
IsMainTemplate: bool, is a "project include" or not
File name: name of the .lst file
The RepositoryItem constructor requires: string internalID, string descriptor, string type, DateTime lastModificationUTC.
What I have now is:
public class TemplateBaseModel : RepositoryItem
{
// Properties
// we have our own Ids and modification date, override RepositoryItem properties
public new InternalID => $"repository://{{{Id}}}";
public DateTime LastModificationUTC => ModifiedOn;
public TemplateBaseModel() : base($"repository://{{{Guid.NewGuid()}}}", /* ?? */, RepositoryItemType.ProjectList.Value, DateTime.Now) { }
public TemplateBaseModel(string internalID, string descriptor, string type, DateTime lastModificationUTC) : base(internalID, descriptor, type, lastModificationUTC) { }
}
In the documentation I can only find what it is (internal metadata that is serialized into a string, and can be edited with the class RepositoryItemDescriptor), but not how it's created or how you can get it, and if I try to debug the example I get (in the CreateOrUpdate() method)#2#PgUAAENoS19QYWNrZWQAeNqd1E1PE1EYxfHfmsTvMAyJEeLY8iKCtpChU5MmvAiOC2NcjDCYmqFtZkaEqF9dXThgsTVGt/fm+Z9zz3lyv3/r2HXlQiFwKVeqDI2NdIVWPdIWCuRGTo2dGRp5ryv0Suq5yKpNoUCllhk5kymMjeS6QtdyldCuHfcs6FgUiQQSqUQgEk3dJY70pF57oS8wURo7N1TIBd64Z0GgY1HfodRA6rXAqVIgdN+SK21tbZlnt4o9J41W2OjNo9Qy72Y421OcVGzvD6R9fQcNcdb7A4WhSm3FQ4GhWu7CimUrt6T5rJvJacruHcruHEosldo38PI3ykjmQi7Qk4ilYoElJ/qOvTJwoi+Z4s33daMeeGDJiyna8szs725+zf6vmz8Tf+71U5WJzGmT/5ncucxHhdoXE6VcJVe6lFsWCGdOQzsCb+ds8I3T6R2+2/qv/ZjNvit0IjcxVhmqjZWuDZpXhHfanE2rKzSQCO0o53Ceamn5rGdTrC3Ws6YtkuiJbYts2LJlXWRbbNWayIbEE7E9sZ4Na9Y91vdVR+vWx9+9pa5NmvwKhVaTzQe5U7WWQqX+R+q+TKV20PxI54ZyZ0I7LmXK5t17PkkcOnSkdKxtT6pwLNbVnava0brt6abP1txGfwD+q8AH, which doesn't help either.
Any idea how to properly create a RepositoryItem from a .lst file? or how to create/get the descriptor?
You should try and use the class RepositoryImportUtil from the combit.ListLabel23.Repository namespace. This helper class does all the hard work for you. Given an IRepositoryinterface and the lst file in place, the required code would be something like
IRepository listLabelRepository = <yourRepository>;
using (ListLabel LL = new ListLabel())
{
LL.FileRepository = listLabelRepository;
using (RepositoryImportUtil importUtil = new RepositoryImportUtil(listLabelRepository))
{
importUtil.ImportProjectFileWithDependencies(LL,
#"<PathToRootProject>");
}
}
If this method is not what your require, the helper class has a couple of other methods as well to help you importing existing projects.

How to get Json Api rendering to work with json views in Grails v3.3.3

I have a simple problem and documentation is not helping me resolve it.
I have created a Grails v3.3.3 demo project - and created a simple domain class called JsonApiBook, with 'name' attribute like this
package ttrestapi
import grails.rest.*
#Resource (uri='/jsonApiBook', formats=['json','xml'])
class JsonApiBook {
static constraints = {
}
String name
}
and marked up the URI as the documentation says the JSON API rendering only works with domain classes (and not a controller class).
In my bootstrap I have saved a instance of book to the tables - and can view that generally.
In my views directory I have a created jsonApiBook folder and created two gson files.
A '_jsonApIBook' template like this
import ttrestapi.JsonApiBook
model {
JsonApiBook book
}
json jsonapi.render(book)
which invokes the jsonapi helper object to render the instance.
I have in the same directory created an index.json like this:
import ttrestapi.Book
model {
List<Book> bookList
}
// We can use template namespace
// method with a Collection.
json tmpl.book(bookList)
When I run the app and use postman or browser to render then I get a result but its Json api compliant (I think it's ignored the template).
So localhost:8080/jsonApiBook just returns (looks default layout):
[
{
"id": 1,
"name": "json api book3"
}
]
and localhost:8080/jsonApiBook/1 just returns 'null' which can't be right.
How should I be setting up the json views for rendering JSON API compliant output? As this doesn't appear to work correctly.
build.gradle
buildscript {
....
dependencies {
........
classpath "org.grails.plugins:views-gradle:1.2.7"
}
}
--
apply plugin: "org.grails.grails-web"
apply plugin: "org.grails.plugins.views-json"
dependencies {
. . .
compile "org.grails.plugins:views-json:1.2.7"
. . .
}
Domain JsonApiBook.groovy
import grails.rest.Resource
#Resource (uri='/jsonApiBook', formats=['json','xml'])
class JsonApiBook {
String name
static constraints = {
}
}
Bootstrap.groovy
class BootStrap {
def init = { servletContext ->
new JsonApiBook(name: 'first').save(flush:true)
new JsonApiBook(name: 'second').save(flush:true)
new JsonApiBook(name: 'third').save(flush:true)
new JsonApiBook(name: 'fourth').save(flush:true)
new JsonApiBook(name: 'fifth').save(flush:true)
}
def destroy = {
}
}
Created folder under view called jsonApiBook
Created template named _jsonApiBook.gson in jsonApiBook folder
model {
JsonApiBook jsonApiBook
}
json {
name jsonApiBook.name
}
created show.gson under same folder
model {
JsonApiBook jsonApiBook
}
json g.render(template:"jsonApiBook", model:[jsonApiBook:jsonApiBook])
When i run http://localhost:8080/jsonApiBook i get bellow:
When i run http://localhost:8080/jsonApiBook/1 i get bellow:
Note: I used grails 3.3.3 with h2 memory DB
Reference
Hope this helps you
ok - got to similar place today on the train. Essentially the convention over configuration is core to whats happening here.
First the #Resource annotation generates a default RestfulController for you. In this approach the default base template _resourceClassName.gson expects the model variable to have the same name as the resource type so my original example instead of 'book'
import ttrestapi.JsonApiBook
model {
JsonApiBook book
}
json jsonapi.render(book)
it should really read as (following convention)
import ttrestapi.JsonApiBook
// variable should be same name as the Class name starting with lowercase
// as default (it can be different but the caller has to change how the
// the template parameter is invoked
model {
JsonApiBook jsonApiBook
}
json jsonapi.render(jsonApiBook)
Then the index.gson should have read as modified below
import ttrestapi.JsonBookApi
//note although not obvious in the written docs which use the show command, the
// default expected model variable is <resourceClass>List
model {
List<JsonBookApi> jsonBookApiList
}
// We can use template namespace
// method with a Collection.
json tmpl.jsonBookApi (jsonBookApiList )
If you want to use another variable name then in the base template you'd have to declare that name as map when calling the base template, from the index.gson . e.g. say the variable name in the base template was
model {
JsonBookApi myBook...
then when calling this template from my index.gson you would put something like this
...
model {
List<JsonBookApi> jsonBookApiList
}
json tmpl.jsonBookApi ("myBook", jsonBookApiList )
this invokes the correct template _jsonBookApi, but takes the model variable default in the index.gson and forces it to bind the value of jsonBookApiList to the myBook variable in the base template (_jsonBookApi.gson).
With the default generation of a controller, using #Resource annotation, the model variable will always be 'resourceClassName'List
I think the only way to change that is not to use the #Resource annotation on your domain class, but to use the URL mappings configuration to map your uri to a controller, and then you have to create a controller yourself by hand and ensure you extend from RestfulController. doing this you can override the default model variable name by implementing an overidden 'index()' method and ensuring you explicitly name the model variable you want, and ensure that the index.gson model variable is exactly the same as that set in your controller.
however the key point was I was not following the core convention defaults so the code as originally built couldn't work and returned null.
when you start out the documentation isn't absolutely clear what bits are part of the convention, and in the examples (which use show.gson) don't tell you what the model variable default name will be for the index.gson (add List to end) so its quite easy to get lost

howto: optional (nested) class property?

I have a class which I want to have some optional nested properties.
class Input {
stuff {
first_name?: string; // optional
};
however it seems that isn't legal typescript. ; expected
Next is to pull stuff out into an interface
interface IFrom {
id: any;
first_name?: string;
};
class Input {
from:IFrom;
however when i put these in the same file I get
tsPublic property 'from' of exported class has or is using private name 'IFrom'.
I can't make public interface
'public' modifier cannot appear on a module element.
What I've ended up doing is putting the interface in yet another file, but this is getting to be astronaut engineering where every struct and property needs to be in its own file...
Am I missing something about how best to do this?
I want the first_name property to be public but part of a struct.
Want it to be optional.
Prefer fewer individual files.
Thanks!
however it seems that isn't legal typescript. ; expected
The syntax for inline types is incorrect. You are missing a :. The following works fine:
class Input {
stuff: {
first_name?: string; // optional
};
}
That answers the question. But since you tried more stuff:
Public property 'from' of exported class has or is using private name 'IFrom'.
You probably have export class ... that means that you need to do export interface too to export any interface that the class uses.
You should use the keyword export with interfaces and classes, not public.
Here is an example:
module ModuleA {
export interface IFrom {
id: any;
first_name?: string;
}
}
module ModuleB {
export class Input {
from:ModuleA.IFrom;
}
}
var input = new ModuleB.Input();
input.from = {id: 123, first_name: 'Bob'};
alert(input.from.first_name); // Bob

How can I selectively apply a VSTemplate?

I am creating a custom VSTemplate for MVC 4 applications for my company that uses a wizard that is comparable to the wizard that appears when you create a new MVC4 application. I have one of two templates I would like to apply when the developer creates a new app of this type as shown here:
Both of those entries correspond to templates that are defined inside my VSIX project under a folder called ProjectTemplates:
My question is, how do I apply the correct template when the wizard runs? I know how to create a vstemplate with multiple projects (using the ProjectCollection node in the vstemplate), but that's not really what I want to do since they will never be deployed together. I see that I can add both vstemplates as Assets to my vsixmanifest file, but I'm not really sure how to apply just one template conditionally.
Thanks!
You'll need to include the files for your "optional" template(s) in sub directories of the the "root" template folder but EXCLUDE them from the TemplateContent Element of the "root" template.
Your IWizard implementation needs to keep a reference to the EnvDTE.DTE object (the first parameter of RunStarted) and use it in the ProjectFinishedGenerating to add the projects to the solution using the template(s) that match what the user selected.
public class SelectTemplatesWizard : IWizard
{
private EnvDTE.DTE _dte = null;
private string _solutionDir = null;
private string _templateDir = null;
public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
{
// Store the reference to the environment for later use
_dte = automationObject as EnvDTE.DTE;
/*
The value of the item in the replacements dictionary for the key
$destinationdirectory$ is populated with the physical location of
the directory (named based on the user entered project name) created
sibling to the solution file.
The solution directory will be this directories parent
when the Type attribute of the VSTemplate element is ProjectGroup
*/
_solutionDir = System.IO.Path.GetDirectoryName(replacementsDictionary["$destinationdirectory$"]);
// customParams[0] is a default custom param that contains the physical location of the template that is currently being applied
_templateDir = System.IO.Path.GetDirectoryName(customParams[0] as string);
}
public void ProjectFinishedGenerating(Project project)
{
int userSelected = 1;
string name= null, projectPath= null, templatePath = null;
switch (userSelected)
{
case 0:
{
name = "Angular";
projectPath = System.IO.Path.Combine(_solutionDir, "Angular");
templatePath = System.IO.Path.Combine(_templateDir , "Angular\Angular.vstemplate");
}
break;
case 1:
{
name = "MVC4";
projectPath = System.IO.Path.Combine(_solutionDir, "MVC4");
templatePath = System.IO.Path.Combine(_templateDir , "MVC4\MVC4.vstemplate");
}
break;
}
_dte.Solution.AddFromTemplate(templatePath, projectPath, name);
}
/* Other IWizard methods excluded for brevity */
}