@team-supercharge/oasg 14.1.0-feature-csharp-functions-2e109dee.0 → 14.1.0-feature-python-fastapi-6dc5992a.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -683,6 +683,27 @@ TBD
683
683
 
684
684
  Publishing the PyPI packages is done with Twine. For authentication againts the PiPI repository you need to set the `TWINE_USERNAME` and `TWINE_PASSWORD` environment variables.
685
685
 
686
+
687
+ #### `python-fastapi`
688
+
689
+ ```json
690
+ {
691
+ "id": "server-python",
692
+ "type": "python-fastapi",
693
+ "source": "source-merged",
694
+ "packageName": "oasg_example",
695
+ "repositoryUrl": "https://gitlab.supercharge.io/api/v4/projects/1226/packages/pypi"
696
+ }
697
+ ```
698
+
699
+ |Parameter| Description| Required | Default |
700
+ |-|-|-|-|
701
+ | packageName | Package nem for the project (convention: snake_case) | Y | - |
702
+ | repositoryUrl | URL of the PyPI repository | Y | - |
703
+
704
+ Building the distribution package requires Flit.
705
+ Publishing the PyPI packages is done with Twine. For authentication againts the PiPI repository you need to set the `TWINE_USERNAME` and `TWINE_PASSWORD` environment variables.
706
+
686
707
  #### `contract-testing`
687
708
 
688
709
  ```json
package/bin/exec.js CHANGED
@@ -11,4 +11,15 @@ function exec(command, stdio) {
11
11
  }
12
12
  }
13
13
 
14
+ function bash(command, stdio) {
15
+ try {
16
+ execSync(`bash -e -c "${command}"`, { stdio: stdio || 'inherit' });
17
+ }
18
+ catch (e) {
19
+ console.error(e.message);
20
+ exit(1);
21
+ }
22
+ }
23
+
14
24
  exports.exec = exec;
25
+ exports.bash = bash;
package/bin/oasg CHANGED
@@ -15,6 +15,7 @@ const expressHttpProxy = require('express-http-proxy');
15
15
  const { exit } = require('process');
16
16
 
17
17
  const { exec } = require(`${__dirname}/exec.js`);
18
+ const { bash } = require(`${__dirname}/exec.js`);
18
19
  const { merge } = require(`${__dirname}/merger.js`);
19
20
  const { applyOverrides } = require(`${__dirname}/overrider.js`);
20
21
  const { openApiTarget } = require(`${__dirname}/openapi-target.js`);
@@ -46,6 +47,7 @@ const DEFAULT_GENERATOR_MAPPING = {
46
47
  "nestjs": { version: '7.0.1', generator: 'typescript-angular' },
47
48
  "spring": { version: '7.0.1', generator: 'spring' },
48
49
  "spring-kotlin": { version: '7.0.1', generator: 'kotlin-spring' },
50
+ "python-fastapi": { version: '7.0.1', generator: 'python-fastapi' },
49
51
  "dotnet": { version: '7.8.0', generator: 'csharp-functions' },
50
52
  // misc targets
51
53
  "contract-testing": { version: '4.3.1', generator: 'typescript-node' },
@@ -550,9 +552,9 @@ function fetchBinary(target) {
550
552
 
551
553
  // download binary
552
554
  console.log(`... downloading ${binary.url} ==> ${binaryPath}`);
553
- exec(`mkdir -p ${BIN_FOLDER}`);
554
- exec(`wget ${binary.url} -q -O ${binaryPath}`);
555
- exec(`chmod +x ${binaryPath}`);
555
+ bash(`mkdir -p ${BIN_FOLDER}`);
556
+ bash(`wget ${binary.url} -q -O ${binaryPath}`);
557
+ bash(`chmod +x ${binaryPath}`);
556
558
  return binaryPath;
557
559
  }
558
560
 
@@ -583,9 +585,9 @@ function fetchFormatter(target) {
583
585
 
584
586
  // download binary
585
587
  console.log(`... downloading ${binary.url} ==> ${binaryPath}`);
586
- exec(`mkdir -p ${BIN_FOLDER}`);
587
- exec(`wget ${binary.url} -q -O ${binaryPath}`);
588
- exec(`chmod +x ${binaryPath}`);
588
+ bash(`mkdir -p ${BIN_FOLDER}`);
589
+ bash(`wget ${binary.url} -q -O ${binaryPath}`);
590
+ bash(`chmod +x ${binaryPath}`);
589
591
  return binaryPath;
590
592
  }
591
593
 
@@ -596,12 +598,12 @@ function customizeTemplates(target) {
596
598
  const targetTemplateDir = `${__dirname}/../targets/${target.type}/templates`;
597
599
 
598
600
  if (fs.existsSync(templateDir)) {
599
- exec(`rm -rf ${templateDir}`);
601
+ bash(`rm -rf ${templateDir}`);
600
602
  }
601
- exec(`mkdir -p ${templateDir}`);
603
+ bash(`mkdir -p ${templateDir}`);
602
604
 
603
605
  if (fs.existsSync(targetTemplateDir)) {
604
- exec(`cp -R ${targetTemplateDir}/* ${templateDir}`);
606
+ bash(`cp -R ${targetTemplateDir}/* ${templateDir}`);
605
607
  }
606
608
 
607
609
  if (target.templateDir) {
@@ -610,7 +612,7 @@ function customizeTemplates(target) {
610
612
  exit(1);
611
613
  }
612
614
 
613
- exec(`cp -R ${target.templateDir}/* ${templateDir}`);
615
+ bash(`cp -R ${target.templateDir}/* ${templateDir}`);
614
616
  }
615
617
 
616
618
  return templateDir;
package/config.schema.yml CHANGED
@@ -20,6 +20,7 @@ properties:
20
20
  - $ref: '#/targets/Android'
21
21
  - $ref: '#/targets/ios'
22
22
  - $ref: '#/targets/Python'
23
+ - $ref: '#/targets/PythonFastApi'
23
24
  - $ref: '#/targets/ContractTesting'
24
25
  - $ref: '#/targets/NestJS'
25
26
  - $ref: '#/targets/OpenAPI'
@@ -297,6 +298,20 @@ targets:
297
298
  - packageName
298
299
  - repositoryUrl
299
300
 
301
+ PythonFastApi:
302
+ allOf:
303
+ - $ref: '#/targets/Base'
304
+ - properties:
305
+ type:
306
+ pattern: "^python-fastapi$"
307
+ packageName:
308
+ type: string
309
+ repositoryUrl:
310
+ type: string
311
+ required:
312
+ - packageName
313
+ - repositoryUrl
314
+
300
315
  ContractTesting:
301
316
  allOf:
302
317
  - $ref: '#/targets/Base'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-supercharge/oasg",
3
- "version": "14.1.0-feature-csharp-functions-2e109dee.0",
3
+ "version": "14.1.0-feature-python-fastapi-6dc5992a.0",
4
4
  "description": "Node-based tool to lint OpenAPI documents and generate clients, servers and documentation from them",
5
5
  "author": "Supercharge",
6
6
  "license": "MIT",
package/targets/common.sh CHANGED
@@ -1,3 +1,5 @@
1
+ #!/bin/bash
2
+
1
3
  # command line arguments:
2
4
  # 1. version - semantic version string
3
5
  # 2. binary - openapi-generator JAR file
@@ -21,10 +23,11 @@ templateDir=$9
21
23
 
22
24
  echo -e "\n=====\n version:\t$version\n binary:\t$binary\n configFile:\t$configFile\n targetId:\t$targetId\n generatorId:\t$generatorId\n openApiFile:\t$openApiFile\n formatter:\t$formatterBinary\n preRelease:\t$preRelease\n templateDir:\t$templateDir\n ---"
23
25
 
24
- for paramName in $(cat $configFile | jq -r ".targets[] | select(.id==\"$targetId\") | del(.id) | del(.type) | del(.source) | del(.generator) | del(.generatorId) | del(.templateDir) | keys | .[]"); do
25
- result=$(cat $configFile | jq -r ".targets[] | select(.id==\"$targetId\") | .$paramName")
26
- echo -e " $paramName:\t$result"
27
- eval $paramName="'$result'"
28
- done
26
+ blacklist='.id, .type, .source, .generator, .generatorId, .templateDir'
27
+
28
+ params=$(jq -r ".targets[] | select(.id == \"$targetId\") | del($blacklist) | to_entries | map(\"\(.key)=\(.value | @sh);\") | .[]" $configFile)
29
+
30
+ echo "$params"
31
+ eval $params
29
32
 
30
33
  echo -e "=====\n"
@@ -2,9 +2,12 @@
2
2
 
3
3
  source $(dirname "$0")/../common.sh
4
4
 
5
- # change npm pre-release syntax (with - after semver) to python local syntax (with + after semver)
6
- version=$(echo $version | sed 's/-/\+/')
7
- echo "[NOTE] version updated to: ${version}"
5
+ # if the version contains a `-` character, then use PEP 440 beta version syntax
6
+ # example: 1.0.0-beta.1 -> 1.0.0b0+beta.1
7
+ if [[ $version == *"-"* ]]; then
8
+ version=$(echo $version | sed 's/-/b0+/')
9
+ echo "[NOTE] version updated to: ${version}"
10
+ fi
8
11
 
9
12
  rm -rf out/$targetId
10
13
  mkdir -p out/$targetId
@@ -0,0 +1,32 @@
1
+ #/bin/bash
2
+
3
+ source $(dirname "$0")/../common.sh
4
+
5
+ # if the version contains a `-` character, then use PEP 440 beta version syntax
6
+ # example: 1.0.0-beta.1 -> 1.0.0b0+beta.1
7
+ if [[ $version == *"-"* ]]; then
8
+ version=$(echo $version | sed 's/-/b0+/')
9
+ echo "[NOTE] version updated to: ${version}"
10
+ fi
11
+
12
+ rm -rf out/$targetId
13
+ mkdir -p out/$targetId
14
+
15
+ java -jar $binary generate \
16
+ -g $generatorId \
17
+ -i $openApiFile \
18
+ -t $templateDir \
19
+ -o out/$targetId \
20
+ -c $(dirname "$0")/generator-config.json \
21
+ -p "packageVersion=$version,packageName=$packageName" $generatorCustomArgs
22
+
23
+ cd out/$targetId
24
+
25
+ touch "src/$packageName/__init__.py"
26
+ python3 -m venv venv
27
+ source venv/bin/activate
28
+ pip install --upgrade pip
29
+ pip install flit==3.9.0
30
+ flit build --no-use-vcs
31
+
32
+ cd ../../
@@ -0,0 +1,7 @@
1
+ {
2
+ "inlineSchemaOptions": {
3
+ "ARRAY_ITEM_SUFFIX": "",
4
+ "MAP_ITEM_SUFFIX": "",
5
+ "SKIP_SCHEMA_REUSE": "true"
6
+ }
7
+ }
@@ -0,0 +1,9 @@
1
+ #/bin/bash
2
+
3
+ source $(dirname "$0")/../common.sh
4
+
5
+ cd out/$targetId
6
+ source venv/bin/activate
7
+ pip install importlib_metadata==7.2.1 twine==4.0.2
8
+ python3 -m twine upload --repository-url $repositoryUrl dist/*
9
+ cd ../..
@@ -0,0 +1,43 @@
1
+ # OpenAPI generated FastAPI server
2
+
3
+ This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
4
+
5
+ - API version: {{appVersion}}
6
+ {{^hideGenerationTimestamp}}
7
+ - Build date: {{generatedDate}}
8
+ {{/hideGenerationTimestamp}}
9
+ - Build package: {{generatorClass}}
10
+
11
+ ## Requirements.
12
+
13
+ Python >= {{{generatorLanguageVersion}}}
14
+
15
+ ## Installation & Usage
16
+
17
+ To run the server, please execute the following from the root directory:
18
+
19
+ ```bash
20
+ pip3 install -r requirements.txt
21
+ pip3 install uvicorn
22
+ uvicorn --app-dir src {{packageName}}.main:app --host 0.0.0.0 --port {{serverPort}}
23
+ ```
24
+
25
+ and open your browser at `http://localhost:{{serverPort}}/docs/` to see the docs.
26
+
27
+ ## Running with Docker
28
+
29
+ To run the server on a Docker container, please execute the following from the root directory:
30
+
31
+ ```bash
32
+ docker-compose up --build
33
+ ```
34
+
35
+ ## Tests
36
+
37
+ To run the tests:
38
+
39
+ ```bash
40
+ pip3 install pytest
41
+ pip3 install httpx
42
+ PYTHONPATH=src pytest tests
43
+ ```
@@ -0,0 +1,62 @@
1
+ # coding: utf-8
2
+
3
+ from typing import Dict, List # noqa: F401
4
+ import importlib
5
+ import pkgutil
6
+
7
+ from {{apiPackage}}.{{classFilename}}_{{baseSuffix}} import Base{{classname}}
8
+
9
+ from fastapi import ( # noqa: F401
10
+ APIRouter,
11
+ Body,
12
+ Cookie,
13
+ Depends,
14
+ Form,
15
+ Header,
16
+ Path,
17
+ Query,
18
+ Request,
19
+ Response,
20
+ Security,
21
+ status,
22
+ )
23
+
24
+ from {{modelPackage}}.extra_models import TokenModel # noqa: F401
25
+ {{#imports}}
26
+ {{import}}
27
+ {{/imports}}
28
+
29
+ router = APIRouter()
30
+
31
+ {{#operations}}
32
+ {{#operation}}
33
+ @router.{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}(
34
+ "{{path}}",
35
+ responses={
36
+ {{#responses}}
37
+ {{code}}: {{=<% %>=}}{<%#dataType%>"model": <%dataType%>, "description": "<%message%>"<%/dataType%><%^dataType%>"description": "<%message%>"<%/dataType%>}<%={{ }}=%>,
38
+ {{/responses}}
39
+ },
40
+ tags=[{{#tags}}"{{name}}"{{^-last}},{{/-last}}{{/tags}}],
41
+ {{#summary}}
42
+ summary="{{.}}",
43
+ {{/summary}}
44
+ {{#description}}
45
+ description = "{{.}}",
46
+ {{/description}}
47
+ response_model_by_alias=True,
48
+ )
49
+ async def {{operationId}}(
50
+ request: Request,
51
+ {{#allParams}}
52
+ {{>endpoint_argument_definition}},
53
+ {{/allParams}}
54
+ ) -> Response: # -> {{returnType}}{{^returnType}}None{{/returnType}}
55
+ {{#notes}}"""{{.}}"""
56
+ return await Base{{classname}}.subclasses[0]().{{operationId}}(request{{#allParams}}, {{>impl_argument}}{{/allParams}}){{/notes}}{{^notes}}...{{/notes}}
57
+ {{^-last}}
58
+
59
+
60
+ {{/-last}}
61
+ {{/operation}}
62
+ {{/operations}}
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+
3
+ from typing import ClassVar, Dict, List, Tuple # noqa: F401
4
+ from fastapi import Request, Response
5
+
6
+ {{#imports}}
7
+ {{import}}
8
+ {{/imports}}
9
+
10
+ class Base{{classname}}:
11
+ subclasses: ClassVar[Tuple] = ()
12
+
13
+ def __init_subclass__(cls, **kwargs):
14
+ super().__init_subclass__(**kwargs)
15
+ Base{{classname}}.subclasses = Base{{classname}}.subclasses + (cls,)
16
+
17
+ {{#operations}}
18
+ {{#operation}}
19
+ async def {{operationId}}(
20
+ self,
21
+ request: Request,
22
+ {{#allParams}}
23
+ {{>impl_argument_definition}},
24
+ {{/allParams}}
25
+ ) -> Response: # -> {{returnType}}{{^returnType}}None{{/returnType}}
26
+ {{#notes}}"""{{.}}"""
27
+ ...{{/notes}}{{^notes}}...{{/notes}}
28
+ {{^-last}}
29
+
30
+ {{/-last}}
31
+ {{/operation}}
32
+ {{/operations}}
@@ -0,0 +1 @@
1
+ {{#isPathParam}}{{baseName}}{{/isPathParam}}{{^isPathParam}}{{paramName}}{{/isPathParam}}: {{>param_type}} = {{#isPathParam}}Path{{/isPathParam}}{{#isHeaderParam}}Header{{/isHeaderParam}}{{#isFormParam}}Form{{/isFormParam}}{{#isQueryParam}}Query{{/isQueryParam}}{{#isCookieParam}}Cookie{{/isCookieParam}}{{#isBodyParam}}Body{{/isBodyParam}}({{&defaultValue}}{{^defaultValue}}{{#isPathParam}}...{{/isPathParam}}{{^isPathParam}}None{{/isPathParam}}{{/defaultValue}}, description="{{description}}"{{#isQueryParam}}, alias="{{baseName}}"{{/isQueryParam}}{{#isLong}}{{#minimum}}, ge={{.}}{{/minimum}}{{#maximum}}, le={{.}}{{/maximum}}{{/isLong}}{{#isInteger}}{{#minimum}}, ge={{.}}{{/minimum}}{{#maximum}}, le={{.}}{{/maximum}}{{/isInteger}}{{#pattern}}, regex=r"{{.}}"{{/pattern}}{{#minLength}}, min_length={{.}}{{/minLength}}{{#maxLength}}, max_length={{.}}{{/maxLength}})
@@ -0,0 +1,35 @@
1
+ [project]
2
+ name = "{{packageName}}"
3
+ version = "{{packageVersion}}"
4
+ description = "{{appDescription}}"
5
+
6
+ [build-system]
7
+ requires = ["setuptools", "wheel"]
8
+ build-backend = "setuptools.build_meta"
9
+
10
+ [tool.black]
11
+ line-length = 88
12
+ exclude = '''
13
+ (
14
+ /(
15
+ \.eggs # exclude a few common directories in the
16
+ | \.git # root of the project
17
+ | \.hg
18
+ | \.mypy_cache
19
+ | \.tox
20
+ | \.venv
21
+ | _build
22
+ | buck-out
23
+ | build
24
+ | dist
25
+ )/
26
+ )
27
+ '''
28
+
29
+ [tool.isort]
30
+ profile = "black"
31
+ skip = [
32
+ '.eggs', '.git', '.hg', '.mypy_cache', '.nox', '.pants.d', '.tox',
33
+ '.venv', '_build', 'buck-out', 'build', 'dist', 'node_modules', 'venv',
34
+ ]
35
+ skip_gitignore = true
@@ -0,0 +1,2 @@
1
+ fastapi==0.109.2
2
+ pydantic==2.6