generate all script, service integration and injection

This commit is contained in:
Wolfgang Hottgenroth 2021-11-22 19:07:46 +01:00
parent 590e9da904
commit bd85599a98
8 changed files with 132 additions and 21 deletions

14
DbService.cs Normal file
View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
namespace de.hottis.genericdatabaseapiservice.Services {
public interface IDbService {
void JustDoSomething(string msg);
}
public class DbService : IDbService {
public void JustDoSomething(string msg) {
Console.WriteLine(msg);
}
}
}

4
ENV
View File

@ -1 +1,3 @@
PACKAGE_NAME=KROHNE.PdbApiService PACKAGE_NAME=de.hottis.genericdatabaseapiservice
export PACKAGE_NAME

View File

@ -4,9 +4,9 @@ import glob
import argparse import argparse
import os import os
import re import re
import json
from yaml.loader import SafeLoader from yaml.loader import SafeLoader
from generateHelper import CsOperationNameConverter, OpenApiExtractRefType from generateHelper import CsOperationNameConverter, OpenApiExtractRefType, CsTypeConverter
parser = argparse.ArgumentParser(description="generate.py") parser = argparse.ArgumentParser(description="generate.py")
parser.add_argument('--apiDefinitionFile', '-a', parser.add_argument('--apiDefinitionFile', '-a',
@ -91,9 +91,18 @@ for path in apiDefinition['paths'].values():
if not statementChecker[method].match(statement): if not statementChecker[method].match(statement):
raise Exception(f"Invalid statement {statement} for method {method}") raise Exception(f"Invalid statement {statement} for method {method}")
inputType = None bodyInputType = {}
if 'requestBody' in operation: if 'requestBody' in operation:
inputType = OpenApiExtractRefType(operation['requestBody']['content']['application/json']['schema']['$ref']) bodyInputTypeName = OpenApiExtractRefType(operation['requestBody']['content']['application/json']['schema']['$ref'])
bodyInputType = { 'apiName': bodyInputTypeName, 'csName': CsOperationNameConverter(bodyInputTypeName) }
paramsInputTypes =[]
if 'parameters' in operation:
for paramsInputType in operation['parameters']:
paramsInputType['type'] = CsTypeConverter(paramsInputType['schema']['type'])
del paramsInputType['schema']
paramsInputTypes.append(paramsInputType)
operations.append({ operations.append({
'description': description, 'description': description,
'method':method, 'method':method,
@ -103,9 +112,10 @@ for path in apiDefinition['paths'].values():
'allSelector': operation['operationId'].endswith('all'), 'allSelector': operation['operationId'].endswith('all'),
'byIdSelector': operation['operationId'].endswith('byid'), 'byIdSelector': operation['operationId'].endswith('byid'),
'statement': statement, 'statement': statement,
'inputType': { 'apiName': inputType, 'csName': CsOperationNameConverter(inputType) } if inputType else {} 'bodyInputType': bodyInputType,
'paramsInputTypes': paramsInputTypes
}) })
print(f"{operations=}") #print(f"{operations=}")
apiDefinition["operations"] = operations apiDefinition["operations"] = operations
types = {} types = {}
@ -123,9 +133,10 @@ for (typeName, typeDefinition) in apiDefinition['components']['schemas'].items()
'csName': typeName.capitalize(), 'csName': typeName.capitalize(),
'properties': typeProperties 'properties': typeProperties
} }
print(f"{types=}") #print(f"{types=}")
apiDefinition['types'] = types apiDefinition['types'] = types
print(json.dumps(apiDefinition, indent=4))
for f in glob.glob(args.template, recursive=True): for f in glob.glob(args.template, recursive=True):
print(f"process {f}") print(f"process {f}")
tmpl = Template(file=f, searchList=[apiDefinition]) tmpl = Template(file=f, searchList=[apiDefinition])

42
generateAll.sh Normal file
View File

@ -0,0 +1,42 @@
#!/bin/bash
# safety measure
if [ -d output ]; then
echo "output directory already exist"
echo "remove manually and try again"
fi
# PACKAGE_NAME will be loaded here
. ENV
# generate server code and endpoint stubs from openapi.yaml
docker run -it --rm -v $PWD:/work -u $UID openapitools/openapi-generator:cli-v5.1.0 \
generate -i /work/openapi.yaml -g aspnetcore -o /work/output \
--package-name $PACKAGE_NAME \
--additional-properties="packageVersion=0.0.1,aspnetCoreVersion=5.0,operationIsAsync=true,modelPropertyNaming=camelCase,\
generateBody=false,classModifier=abstract,operationModifier=abstract"
# patch DbService registering into generated startup code
sed -i output/src/$PACKAGE_NAME/Startup \
-e 's/\(using '$PACKAGE_NAME'.OpenApi;\)/\1\nusing '$PACKAGE_NAME'.Services;/'\
-e 's#\(// Add framework services.\)#services.AddTransient<IDbService, DbService>();\n\1#'
# create directories for manually developed code
mkdir output/src/$PACKAGE_NAME/Implementations
mkdir output/src/$PACKAGE_NAME/Services
# copy database service into source code try
cp DbService.cs output/src/$PACKAGE_NAME/Services
# generate endpoint code from openapi.yaml
python3.10 generate.py
# copy endpoint code into source code try
cp regular.cs output/src/$PACKAGE_NAME/Implementations

View File

@ -7,6 +7,13 @@ def JsNameConverter(i):
def CsOperationNameConverter(i): def CsOperationNameConverter(i):
return ''.join([capitalizeOnlyFirstLetter(x) for x in i.split('.')]) if i else i return ''.join([capitalizeOnlyFirstLetter(x) for x in i.split('.')]) if i else i
def CsTypeConverter(i):
r = i
match (i):
case 'integer':
r = 'int'
return r
def OpenApiExtractRefType(i): def OpenApiExtractRefType(i):
e = i.split('/') e = i.split('/')
if e[:-1] == ['#', 'components', 'schemas']: if e[:-1] == ['#', 'components', 'schemas']:

View File

@ -1,7 +1,7 @@
openapi: 3.0.0 openapi: 3.0.0
info: info:
title: PDB API title: Generic Database API Service
version: "0.0.2" version: "0.0.2"
paths: paths:

View File

@ -16,7 +16,7 @@ Configuration details for generator: https://openapi-generator.tech/docs/generat
Build and run the stub webservice: Build and run the stub webservice:
docker run -it --rm -p 8080:8080 -v $PWD:/work \ docker run -it --rm -p 8080:8080 -v $PWD:/work \
devnexus.krohne.com:18079/repository/docker-krohne/dotnetcoresdkenv:5.0 \ registry.hottis.de/dockerized/dotnetcore5sdk:1.0.0 \
bash bash
ATTENTION: This won't work with a set UID ATTENTION: This won't work with a set UID
@ -27,5 +27,12 @@ Build:
Run: Run:
dotnet run -p src/KROHNE.ManufacturingCycleReportWebService/KROHNE.ManufacturingCycleReportWebService.csproj dotnet run -p src/$PACKAGE_NAME/$PACKAGE_NAME.csproj
From output/src/$PACKAGE_NAME:
* dotnet add package MySqlConnector --version 2.0.0
* make implementations directory
* copy generate endpoint implementation code to implementations directory

View File

@ -11,20 +11,42 @@ using Newtonsoft.Json;
using ${env['packagename']}.Attributes; using ${env['packagename']}.Attributes;
using ${env['packagename']}.Models; using ${env['packagename']}.Models;
using ${env['packagename']}.Controllers; using ${env['packagename']}.Controllers;
using ${env['packagename']}.Services;
namespace ${env['packagename']}.Implementations namespace ${env['packagename']}.Implementations
{ {
/// <summary>
/// </summary>
public class RegularApiImplementation : RegularApiController public class RegularApiImplementation : RegularApiController
{ {
private readonly IDbService _dbService;
public RegularApiImplementation(IDbService dbService) {
_dbService = dbService;
}
#for $operation in $operations #for $operation in $operations
#if $operation['method'] == 'get' #if $operation['method'] == 'get'
/// <summary>
/// $operation['description']
/// </summary>
public override IActionResult ${operation['func']}( #slurp public override IActionResult ${operation['func']}( #slurp
#if $operation['byIdSelector'] #if $operation['paramsInputTypes']
INSERT CODE TO GET ID #slurp #set $sep = ""
#elif $operation['inputType'] #for $paramsInputType in $operation['paramsInputTypes']
[FromBody]$operation['inputType']['csName'] inputItem #slurp $sep [FromRoute (Name = "$paramsInputType['name']")] #slurp
#if $paramsInputType['required']
[Required] #slurp
#end if
$paramsInputType['type'] $paramsInputType['name'] #slurp
#set $sep = ","
#end for
#elif $operation['bodyInputType']
[FromBody]$operation['bodyInputType']['csName'] $operation['bodyInputType']['apiName'] #slurp
#end if #end if
) { ) {
_dbService.JustDoSomething("Hello ${operation['func']}");
// Statement: // Statement:
#if not $operation['statement'] #if not $operation['statement']
// SELECT // SELECT
@ -37,9 +59,9 @@ namespace ${env['packagename']}.Implementations
#else #else
// $operation['statement'] // $operation['statement']
#end if #end if
#if $operation['inputType'] #if $operation['bodyInputType']
// Input type mapping: $operation['inputType']['apiName'] -> $operation['inputType']['csName'] // Input type mapping: $operation['bodyInputType']['apiName'] -> $operation['bodyInputType']['csName']
#for $property in $types[$operation['inputType']['apiName']]['properties'] #for $property in $types[$operation['bodyInputType']['apiName']]['properties']
// $property['sqlName'] -> $property['csName'] // $property['sqlName'] -> $property['csName']
#end for #end for
#end if #end if
@ -51,11 +73,17 @@ namespace ${env['packagename']}.Implementations
#if $operation['isList'] #if $operation['isList']
// result must be mapped in list // result must be mapped in list
#end if #end if
return new ObjectResult(); return new ObjectResult(null);
} }
#elif $operation['method'] == 'post' #elif $operation['method'] == 'post'
bla // INSERT
#elif $operation['method'] == 'put'
// UPDATE
#elif $operation['method'] == 'delete'
// DELETE
#else #else
#raise Exception('invalid method') #raise Exception('invalid method')